openapi: 3.1.0
info:
  title: Leimat Chatbot API
  version: 1.2.0
  summary: API para identificar clientes, buscar productos y consultar precios/stock consolidados.
  description: |
    Contrato de integración entre Leimat y Darwin AI para asistir conversaciones comerciales
    sobre clientes, productos, precios y disponibilidad.

    La API está orientada a un flujo conversacional de pre-venta o atención comercial:
    primero autenticar al integrador, luego identificar al cliente a partir del teléfono de
    contacto, después resolver el producto consultado y finalmente obtener una vista de precio
    y stock contextualizada para ese cliente.

    El objetivo del contrato es ofrecer respuestas simples, determinísticas y consumibles por
    un agente conversacional, minimizando ambigüedades en identificación de cliente, selección
    de producto y obtención de condiciones comerciales vigentes.

servers:
  - url: https://api.chatbot.leimat.com.ar
    description: Entorno Prod
tags:
  - name: autenticacion
    description: Emision de credenciales de acceso para consumir la API
  - name: clientes
    description: Operaciones de identificación y datos de cuenta
  - name: productos
    description: Catálogo, precios y disponibilidad de stock

security:
  - bearerAuth: []

paths:
  # REQUERIMIENTO 0: Obtención de Access Token
  /auth/login:
    post:
      tags: [autenticacion]
      operationId: obtenerAccessToken
      summary: Genera un token de acceso JWT.
      description: Permite al chatbot autenticarse enviando sus credenciales para obtener el token requerido por el resto de la API. El token emitido debe ser conservado por el integrador y reutilizado hasta su vencimiento. Si una petición posterior responde 401, el integrador debe solicitar un nuevo token y reintentar una sola vez.
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthLoginRequest'
      responses:
        '200':
          description: Autenticación exitosa. Retorna el token de acceso.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthTokenResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'

  # REQUERIMIENTO 1: Identificación con CUIT
  /cliente/identificar/{telefono}:
    get:
      tags: [clientes]
      operationId: identificarClientePorTelefono
      summary: Identifica cliente por teléfono de WhatsApp.
      description: Retorna los datos del cliente, incluyendo ahora el CUIT/Identificador fiscal.
      parameters:
        - name: telefono
          in: path
          required: true
          description: Teléfono entrante (acepta formatos con +, espacios o guiones).
          schema:
            type: string
            minLength: 7
            maxLength: 30
      responses:
        '200':
          description: Cliente identificado exitosamente.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClienteIdentificado'
        '404':
          $ref: '#/components/responses/NotFound'

  # REQUERIMIENTO 2 - PARTE A: Búsqueda de productos
  /productos/buscar:
    get:
      tags: [productos]
      operationId: buscarProductos
      summary: Busca productos por nombre o coincidencia.
      description: Permite al chatbot obtener el ID de un producto cuando el usuario no lo conoce. La búsqueda devuelve entre 0 y limit resultados, ordenados por código de producto ascendente. Un array vacío indica que no se encontraron coincidencias. Múltiples resultados son válidos y deben ser procesados por el chatbot para refinar o continuar la conversación.
      parameters:
        - name: q
          in: query
          required: true
          description: Término de búsqueda (ej. "inversor", "bateria", "panel solar").
          schema:
            type: string
            minLength: 3
            maxLength: 80
        - name: limit
          in: query
          required: false
          description: Cantidad máxima de resultados a devolver. Si no se informa, se asume 10. El máximo permitido es 20.
          schema:
            type: integer
            minimum: 1
            maximum: 20
            default: 10
      responses:
        '200':
          description: Lista acotada de productos encontrados, ordenada por código de producto ascendente.
          content:
            application/json:
              schema:
                type: array
                maxItems: 20
                items:
                  $ref: '#/components/schemas/ProductoBasico'
              examples:
                sin_resultados:
                  summary: Búsqueda sin coincidencias
                  value: []
                multiples_coincidencias:
                  summary: Búsqueda con varias coincidencias válidas
                  value:
                    - id_producto: 1002101
                      nombre_producto: "INVERSOR SOLAR EOS 24V 1500W"
                      value: "PV30-1.5K"
                    - id_producto: 1002102
                      nombre_producto: "INVERSOR SOLAR EOS 24V 3000W"
                      value: "PV30-3K"
        '400':
          $ref: '#/components/responses/ValidationError'

  # REQUERIMIENTO 2 - PARTE B: Vista Consolidada
  /productos/detalle-completo/{id_producto}:
    get:
      tags: [productos]
      operationId: obtenerDetalleCompletoProducto
      summary: Obtiene vista consolidada de precio y stock.
      description: Combina la información de precio (según lista) y el stock en todas las sucursales.
      parameters:
        - name: id_producto
          in: path
          required: true
          schema:
            type: integer
        - name: id_lista
          in: query
          required: true
          description: ID de la lista de precios del cliente identificado.
          schema:
            type: integer
      responses:
        '200':
          description: Detalle completo del producto.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductoDetalleCompleto'
        '404':
          $ref: '#/components/responses/NotFound'

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

  schemas:
    AuthLoginRequest:
      type: object
      required: [client_id, client_secret]
      properties:
        client_id:
          type: string
          description: Identificador del cliente integrador autorizado.
          example: "chatbot_leimatsa"
        client_secret:
          type: string
          format: password
          description: Secreto compartido del integrador.
          example: "s3cr3t_key_2026"

    AuthTokenResponse:
      type: object
      required: [access_token, token_type, expires_in]
      properties:
        access_token:
          type: string
          description: Token JWT para incluir en el header Authorization.
          example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
        token_type:
          type: string
          example: "Bearer"
        expires_in:
          type: integer
          description: Tiempo de vida del token en segundos.
          example: 3600

    ClienteIdentificado:
      type: object
      required: [id_cliente, razon_social, cuit, id_lista]
      properties:
        id_cliente:
          type: integer
        nombre_contacto:
          type: string
        razon_social:
          type: string
        cuit:
          type: string
          description: "Identificador fiscal (formato limpio: XX-XXXXXXXX-X o solo números)."
          example: "20-12345678-9"
        id_lista:
          type: integer
        nombre_lista:
          type: string
        telefono_normalizado:
          type: string

    ProductoBasico:
      type: object
      required: [id_producto, nombre_producto, value]
      properties:
        id_producto:
          type: integer
        nombre_producto:
          type: string
        value:
          type: string
          description: "Código del producto en iDempiere (M_Product.Value)."

    ProductoDetalleCompleto:
      type: object
      required: [producto, precio, stock_por_sucursal]
      properties:
        producto:
          $ref: '#/components/schemas/ProductoBasico'
        precio:
          $ref: '#/components/schemas/PrecioProducto'
        stock_por_sucursal:
          type: array
          items:
            $ref: '#/components/schemas/StockSucursal'

    PrecioProducto:
      type: object
      required: [valor_unitario, moneda]
      properties:
        valor_unitario:
          type: number
        moneda:
          type: string
        vigencia:
          type: string
          format: date-time

    StockSucursal:
      type: object
      required: [id_sucursal, sucursal, cantidad_disponible]
      properties:
        id_sucursal:
          type: integer
        sucursal:
          type: string
        cantidad_disponible:
          type: number
        ultima_actualizacion:
          type: string
          format: date-time

    ErrorAuth:
      type: object
      required: [code, message]
      properties:
        code:
          type: string
          example: "INVALID_CREDENTIALS"
        message:
          type: string
          example: "Credenciales inválidas."

    ErrorResponse:
      type: object
      required: [code, message]
      properties:
        code:
          type: string
        message:
          type: string

  responses:
    NotFound:
      description: El recurso solicitado no existe.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    ValidationError:
      description: Error en los parámetros de entrada.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Unauthorized:
      description: Credenciales inválidas o token ausente/expirado. Ante este error, el integrador debe solicitar un nuevo token y reintentar la operación una sola vez.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorAuth'
          examples:
            token_expirado:
              summary: Token vencido o inválido
              value:
                code: "UNAUTHORIZED"
                message: "Token ausente, inválido o expirado."
