openapi: 3.1.0
info:
  title: xFIR API
  version: 0.1.0
  description: |
    Validazione, generazione e conversione del FIR digitale (xFIR) del RENTRI.

    **Disclaimer**: strumento tecnico di verifica formale. Non costituisce
    consulenza ambientale, legale o fiscale e non garantisce l'accettazione
    dei documenti da parte del RENTRI.
  contact:
    email: 1bonsegnaferdinando@gmail.com
servers:
  - url: https://api.example.it
    description: Produzione (sostituire col dominio reale)
  - url: http://localhost:8787
    description: Server locale di sviluppo

security: []

paths:
  /v1/health:
    get:
      summary: Stato del servizio
      responses:
        "200":
          description: Servizio attivo
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  engine_version: { type: string }

  /v1/errors:
    get:
      summary: Catalogo dei codici errore del validatore
      responses:
        "200":
          description: Elenco codici con spiegazione
          content:
            application/json:
              schema:
                type: object
                properties:
                  codes:
                    type: array
                    items:
                      type: object
                      properties:
                        code: { type: string }
                        title: { type: string }
                        explanation: { type: string }

  /v1/validate:
    post:
      summary: Valida un documento xFIR
      description: |
        Accetta XML grezzo (content-type application/xml) o JSON `{"xml": "..."}`.
        Utilizzabile anche senza API key (rate limit del gateway); con API key
        il consumo è conteggiato nel piano.
      security:
        - {}
        - apiKey: []
      requestBody:
        required: true
        content:
          application/xml:
            schema: { type: string }
          application/json:
            schema:
              type: object
              required: [xml]
              properties:
                xml: { type: string }
      responses:
        "200":
          description: Report di validazione (valid può essere false)
          content:
            application/json:
              schema: { $ref: "#/components/schemas/ValidationReport" }
        "400": { $ref: "#/components/responses/BadRequest" }
        "413": { description: Payload oltre il limite }

  /v1/generate:
    post:
      summary: Genera l'XML xFIR da un documento JSON
      security:
        - apiKey: []
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/FirDocument" }
      responses:
        "200":
          description: XML generato (con eventuali warning non bloccanti)
          content:
            application/json:
              schema:
                type: object
                properties:
                  xml: { type: string }
                  warnings:
                    type: array
                    items: { $ref: "#/components/schemas/Issue" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "422":
          description: Modello non valido o regole di business violate
        "429": { $ref: "#/components/responses/QuotaExceeded" }

  /v1/convert:
    post:
      summary: Converte un CSV in xFIR (un documento per riga)
      security:
        - apiKey: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [csv]
              properties:
                csv: { type: string }
      responses:
        "200":
          description: Esito per riga
          content:
            application/json:
              schema:
                type: object
                properties:
                  total: { type: integer }
                  converted: { type: integer }
                  failed: { type: integer }
                  results:
                    type: array
                    items:
                      type: object
                      properties:
                        row: { type: integer }
                        ok: { type: boolean }
                        xml: { type: [string, "null"] }
                        issues:
                          type: array
                          items: { $ref: "#/components/schemas/Issue" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "429": { $ref: "#/components/responses/QuotaExceeded" }

  /v1/usage:
    get:
      summary: Consumo del mese corrente per la API key
      security:
        - apiKey: []
      responses:
        "200":
          description: Consumo corrente
          content:
            application/json:
              schema:
                type: object
                properties:
                  plan: { type: string }
                  monthly_limit: { type: integer }
                  used: { type: integer }
        "401": { $ref: "#/components/responses/Unauthorized" }

  /v1/keys:
    get:
      summary: Elenca le API key dell'utente (JWT Cognito)
      security:
        - cognito: []
      responses:
        "200": { description: Elenco chiavi (mai in chiaro) }
        "401": { $ref: "#/components/responses/Unauthorized" }
    post:
      summary: Crea una API key (la chiave in chiaro è mostrata solo qui)
      security:
        - cognito: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                label: { type: string }
      responses:
        "201": { description: Chiave creata, campo api_key in chiaro }
        "401": { $ref: "#/components/responses/Unauthorized" }

  /v1/keys/{keyId}:
    delete:
      summary: Revoca una API key
      security:
        - cognito: []
      parameters:
        - name: keyId
          in: path
          required: true
          schema: { type: string }
      responses:
        "200": { description: Revocata }
        "404": { description: Non trovata }

  /v1/billing/webhook:
    post:
      summary: Webhook Stripe (firma verificata via STRIPE_WEBHOOK_SECRET)
      responses:
        "200": { description: Evento gestito o ignorato }
        "400": { description: Firma non valida }
        "501": { description: Billing non configurato }

components:
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: x-api-key
    cognito:
      type: http
      scheme: bearer
      bearerFormat: JWT

  responses:
    BadRequest: { description: Richiesta malformata }
    Unauthorized: { description: Autenticazione mancante o non valida }
    QuotaExceeded: { description: Limite mensile del piano raggiunto }

  schemas:
    Issue:
      type: object
      required: [code, message, severity]
      properties:
        code: { type: string, examples: ["BIZ-EER-001"] }
        message: { type: string }
        severity: { type: string, enum: [error, warning] }
        path: { type: string }
        line: { type: integer }

    ValidationReport:
      type: object
      properties:
        valid: { type: boolean }
        errors:
          type: array
          items: { $ref: "#/components/schemas/Issue" }
        warnings:
          type: array
          items: { $ref: "#/components/schemas/Issue" }
        meta:
          type: object
          properties:
            schema: { type: string }
            engine_version: { type: string }
        disclaimer: { type: string }

    Soggetto:
      type: object
      required: [denominazione, codice_fiscale, indirizzo]
      properties:
        denominazione: { type: string }
        codice_fiscale: { type: string, description: "P.IVA (11 cifre) o CF (16)" }
        iscrizione_albo: { type: [string, "null"] }
        indirizzo:
          type: object
          required: [via, comune, provincia, cap]
          properties:
            via: { type: string }
            civico: { type: [string, "null"] }
            comune: { type: string }
            provincia: { type: string, description: "Sigla a 2 lettere" }
            cap: { type: string }

    FirDocument:
      type: object
      required:
        [numero_fir, data_emissione, produttore, trasportatore, destinatario,
         rifiuto, trasporto, destinazione]
      properties:
        numero_fir: { type: string }
        data_emissione: { type: string, format: date }
        produttore: { $ref: "#/components/schemas/Soggetto" }
        trasportatore: { $ref: "#/components/schemas/Soggetto" }
        destinatario: { $ref: "#/components/schemas/Soggetto" }
        intermediario:
          oneOf:
            - { $ref: "#/components/schemas/Soggetto" }
            - { type: "null" }
        rifiuto:
          type: object
          required: [codice_eer, stato_fisico, pericoloso, quantita]
          properties:
            codice_eer: { type: string, examples: ["13 02 08*"] }
            descrizione: { type: [string, "null"] }
            stato_fisico: { type: string, enum: [SP, SNP, FP, L] }
            pericoloso: { type: boolean }
            caratteristiche_pericolo:
              type: array
              items: { type: string, examples: ["HP14"] }
            quantita:
              type: object
              required: [valore]
              properties:
                valore: { type: number }
                unita: { type: string, enum: [kg, l, mc], default: kg }
                peso_verificato_a_destino: { type: boolean, default: false }
        trasporto:
          type: object
          required: [targa_automezzo, data_inizio]
          properties:
            targa_automezzo: { type: string }
            targa_rimorchio: { type: [string, "null"] }
            data_inizio: { type: string, format: date }
            conducente: { type: [string, "null"] }
        destinazione:
          type: object
          required: [operazione]
          properties:
            operazione: { type: string, examples: ["R13"] }
        annotazioni: { type: [string, "null"] }
