<?php
/**
 * NIS2 Agile - Visura Service
 *
 * Estrae dati aziendali da visura camerale PDF tramite AI (upload)
 * oppure tramite CertiSource atti-service.php (ricerca per P.IVA).
 *
 * CertiSource API: https://certisource.it/atti-service.php
 * Auth: Authorization: Bearer CERTISOURCE_API_KEY (cs_pat_...)
 */

class VisuraService
{
    // ─────────────────────────────────────────────────────────────────────────
    // METODI PUBBLICI
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * Estrai dati aziendali da un PDF visura caricato dall'utente (via Claude AI).
     */
    public function extractFromPdf(string $filePath): array
    {
        if (!file_exists($filePath)) {
            throw new RuntimeException('File visura non trovato');
        }

        if (!ANTHROPIC_API_KEY) {
            throw new RuntimeException('Chiave API Anthropic non configurata');
        }

        $base64Pdf = base64_encode(file_get_contents($filePath));

        $response = $this->callClaudeApi([
            [
                'type'   => 'document',
                'source' => [
                    'type'       => 'base64',
                    'media_type' => 'application/pdf',
                    'data'       => $base64Pdf,
                ],
            ],
            [
                'type' => 'text',
                'text' => "Analizza questa visura camerale italiana ed estrai i seguenti dati in formato JSON. Rispondi SOLO con il JSON, senza testo aggiuntivo, senza markdown code blocks.\n\nCampi da estrarre:\n- company_name: ragione sociale completa\n- vat_number: partita IVA (solo numeri, senza prefisso IT)\n- fiscal_code: codice fiscale\n- legal_form: forma giuridica (es. S.R.L., S.P.A., ecc.)\n- address: indirizzo sede legale (via/piazza e numero civico)\n- city: comune sede legale\n- province: sigla provincia (es. MI, RM, TO)\n- zip_code: CAP\n- pec: indirizzo PEC se presente\n- phone: telefono se presente\n- ateco_code: codice ATECO principale se presente\n- ateco_description: descrizione attività ATECO se presente\n- incorporation_date: data di costituzione (formato YYYY-MM-DD)\n- share_capital: capitale sociale in EUR (solo numero)\n- employees_range: stima range dipendenti se indicato (es. \"10-49\", \"50-249\", \"250+\")\n- legal_representative: nome e cognome del legale rappresentante\n\nSe un campo non è presente nella visura, usa null come valore.",
            ],
        ]);

        if (!$response) {
            throw new RuntimeException("Nessuna risposta dall'AI");
        }

        $jsonStr = preg_replace('/^```(?:json)?\s*/i', '', trim($response));
        $jsonStr = preg_replace('/\s*```$/', '', $jsonStr);
        $data    = json_decode($jsonStr, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            error_log('[VISURA_PARSE_ERROR] ' . $jsonStr);
            throw new RuntimeException('Impossibile interpretare i dati estratti dalla visura');
        }

        $data['suggested_sector'] = $this->mapAtecoToNis2Sector(
            $data['ateco_code'] ?? '',
            $data['ateco_description'] ?? ''
        );
        $data['source'] = 'pdf_upload';

        $this->logAiInteraction('visura_extraction', 'Estrazione dati da visura camerale PDF');

        return $data;
    }

    /**
     * Recupera dati aziendali da CertiSource atti-service.php tramite P.IVA.
     *
     * Flusso:
     *   POST ?action=richiesta  → ottieni request ID
     *   GET  ?action=stato      → polling fino a completed
     *   GET  ?action=dati       → structured_data JSON
     */
    public function fetchFromCertiSource(string $vatNumber): array
    {
        $apiKey = defined('CERTISOURCE_API_KEY') ? CERTISOURCE_API_KEY : '';
        if ($apiKey === '') {
            error_log('[CERTISOURCE] API key non configurata (CERTISOURCE_API_KEY)');
            throw new RuntimeException('Servizio visure non disponibile. Inserire i dati manualmente.');
        }

        // ── Step 1: richiesta visura ─────────────────────────────────────────
        $richiesta = $this->callCertiSource('POST', 'richiesta', [
            'vat'  => $vatNumber,
            'type' => 'visura_camerale',
        ]);

        if (empty($richiesta['success'])) {
            $msg = $richiesta['error'] ?? $richiesta['message'] ?? 'Errore richiesta visura';
            throw new RuntimeException('CertiSource: ' . $msg);
        }

        $requestId = (int) $richiesta['id'];
        $status    = $richiesta['status'] ?? 'processing';

        // ── Step 2: polling se non già completato (cache hit) ────────────────
        if ($status !== 'completed') {
            $pollMax = defined('CERTISOURCE_POLL_MAX') ? (int) CERTISOURCE_POLL_MAX : 30;
            $pollSec = defined('CERTISOURCE_POLL_SEC') ? (int) CERTISOURCE_POLL_SEC : 3;

            for ($i = 0; $i < $pollMax; $i++) {
                sleep($pollSec);
                $stato = $this->callCertiSource('GET', 'stato', null, ['id' => $requestId]);

                if (!empty($stato['completed'])) {
                    $status = 'completed';
                    break;
                }
                if (($stato['status'] ?? '') === 'failed') {
                    throw new RuntimeException('CertiSource: elaborazione visura fallita');
                }
            }

            if ($status !== 'completed') {
                throw new RuntimeException('Timeout: visura camerale non disponibile. Riprova tra qualche minuto.');
            }
        }

        // ── Step 3: dati strutturati ─────────────────────────────────────────
        $datiRes = $this->callCertiSource('GET', 'dati', null, ['id' => $requestId]);

        if (empty($datiRes['success']) || empty($datiRes['structured_data'])) {
            throw new RuntimeException('CertiSource: dati strutturati non disponibili');
        }

        return $this->mapStructuredData($datiRes['structured_data'], $vatNumber, $requestId);
    }

    // ─────────────────────────────────────────────────────────────────────────
    // METODI PRIVATI — CertiSource
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * Chiama l'API CertiSource atti-service.php.
     *
     * @param string     $method  GET|POST
     * @param string     $action  action=richiesta|stato|dati|...
     * @param array|null $body    JSON body per POST
     * @param array      $params  Query params extra (es. ['id'=>42])
     */
    private function callCertiSource(string $method, string $action, ?array $body = null, array $params = []): array
    {
        $apiKey  = defined('CERTISOURCE_API_KEY') ? CERTISOURCE_API_KEY : '';
        $baseUrl = defined('CERTISOURCE_API_URL') ? CERTISOURCE_API_URL : 'https://certisource.it/atti-service.php';

        $qs = http_build_query(array_merge(['action' => $action], $params));
        $url = $baseUrl . '?' . $qs;

        $ch = curl_init($url);
        $headers = [
            'Authorization: Bearer ' . $apiKey,
            'Content-Type: application/json',
            'Accept: application/json',
        ];

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 15,
            CURLOPT_HTTPHEADER     => $headers,
        ]);

        if ($method === 'POST' && $body !== null) {
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
        }

        $raw      = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curlErr  = curl_error($ch);
        unset($ch);

        if ($curlErr) {
            throw new RuntimeException('CertiSource connessione: ' . $curlErr);
        }

        if ($httpCode === 402) {
            throw new RuntimeException('CertiSource: credito insufficiente');
        }

        if ($httpCode >= 500) {
            throw new RuntimeException('CertiSource: errore server (HTTP ' . $httpCode . ')');
        }

        $result = json_decode($raw ?: '{}', true);
        if (!is_array($result)) {
            throw new RuntimeException('CertiSource: risposta non valida');
        }

        return $result;
    }

    /**
     * Mappa structured_data CertiSource nel formato interno NIS2 Agile.
     */
    private function mapStructuredData(array $sd, string $vatNumber, int $requestId): array
    {
        $sedeLegale = $this->extractSedeLegale($sd['sedi'] ?? []);
        $ateco      = $this->extractPrimaryAteco($sd['ateco_codes'] ?? []);
        $atecoCode  = $ateco['code'] ?? null;
        $atecoDesc  = $ateco['description'] ?? '';

        return [
            'company_name'         => $sd['ragione_sociale'] ?? null,
            'vat_number'           => $sd['partita_iva'] ?? $vatNumber,
            'fiscal_code'          => $sd['codice_fiscale'] ?? null,
            'legal_form'           => $sd['forma_giuridica'] ?? null,
            'address'              => $sedeLegale['via'] ?? null,
            'city'                 => $sedeLegale['comune'] ?? null,
            'province'             => $sedeLegale['provincia'] ?? null,
            'zip_code'             => $sedeLegale['cap'] ?? null,
            'pec'                  => $sd['pec'] ?? $sedeLegale['pec'] ?? null,
            'phone'                => null,
            'ateco_code'           => $atecoCode,
            'ateco_description'    => $atecoDesc ?: null,
            'incorporation_date'   => null,
            'share_capital'        => isset($sd['capitale_sociale']) ? (float) $sd['capitale_sociale'] : null,
            'employees_range'      => $this->computeEmployeesRange($sd['addetti'] ?? null),
            'legal_representative' => $this->findLegalRepresentative($sd['cariche'] ?? []),
            'suggested_sector'     => $this->mapAtecoToNis2Sector($atecoCode ?? '', $atecoDesc),
            'source'               => 'certisource_atti',
            'certisource_id'       => $requestId,
        ];
    }

    /**
     * Trova la sede legale nell'array sedi.
     */
    private function extractSedeLegale(array $sedi): array
    {
        foreach ($sedi as $sede) {
            if (($sede['tipo'] ?? '') === 'sede_legale') {
                return $sede;
            }
        }
        return $sedi[0] ?? [];
    }

    /**
     * Trova il codice ATECO primario.
     */
    private function extractPrimaryAteco(array $atecos): array
    {
        foreach ($atecos as $a) {
            if (($a['type'] ?? '') === 'primary') {
                return $a;
            }
        }
        return $atecos[0] ?? [];
    }

    /**
     * Calcola il range dipendenti dai dati INPS (ultimo trimestre disponibile).
     */
    private function computeEmployeesRange(?array $addetti): ?string
    {
        if (empty($addetti['trimestri'])) {
            return null;
        }
        $last = end($addetti['trimestri']);
        $n    = (int) ($last['dipendenti'] ?? 0);
        if ($n === 0) return null;
        if ($n < 10)  return '1-9';
        if ($n < 50)  return '10-49';
        if ($n < 250) return '50-249';
        return '250+';
    }

    /**
     * Trova il legale rappresentante tra le cariche.
     */
    private function findLegalRepresentative(array $cariche): ?string
    {
        foreach ($cariche as $c) {
            if (!empty($c['rappresentante_legale']) || str_contains(strtolower($c['ruolo'] ?? ''), 'legale')) {
                return $c['nome'] ?? null;
            }
        }
        // Fallback: primo amministratore
        foreach ($cariche as $c) {
            if (str_contains(strtolower($c['ruolo'] ?? ''), 'ammin')) {
                return $c['nome'] ?? null;
            }
        }
        return null;
    }

    // ─────────────────────────────────────────────────────────────────────────
    // ATECO → SETTORE NIS2 (valori ENUM DB)
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * Mappa codice ATECO + descrizione al settore NIS2 (valori ENUM organizations.sector).
     *
     * Valori validi: energy, transport, banking, health, water, digital_infra,
     *                public_admin, manufacturing, postal, chemical, food, waste,
     *                ict_services, digital_providers, space, research, other
     */
    private function mapAtecoToNis2Sector(string $atecoCode, string $atecoDesc): ?string
    {
        $code2 = substr(preg_replace('/[^0-9]/', '', $atecoCode), 0, 2);
        $desc  = strtolower($atecoDesc);

        $byCode = [
            '35' => 'energy',           // Fornitura energia elettrica, gas
            '06' => 'energy',           // Estrazione petrolio e gas
            '19' => 'energy',           // Raffinazione petrolio
            '49' => 'transport',        // Trasporto terrestre
            '50' => 'transport',        // Trasporto marittimo
            '51' => 'transport',        // Trasporto aereo
            '52' => 'transport',        // Magazzinaggio e attività connesse
            '64' => 'banking',          // Servizi finanziari
            '65' => 'banking',          // Assicurazioni
            '66' => 'banking',          // Attività ausiliarie servizi finanziari
            '86' => 'health',           // Assistenza sanitaria
            '87' => 'health',           // Strutture di assistenza
            '36' => 'water',            // Raccolta e distribuzione acqua
            '37' => 'waste',            // Raccolta e trattamento acque reflue
            '38' => 'waste',            // Raccolta e smaltimento rifiuti
            '61' => 'digital_infra',    // Telecomunicazioni
            '62' => 'ict_services',     // Produzione software e IT
            '63' => 'digital_providers',// Servizi di informazione
            '84' => 'public_admin',     // Pubblica amministrazione
            '53' => 'postal',           // Servizi postali e corrieri
            '20' => 'chemical',         // Fabbricazione prodotti chimici
            '10' => 'food',             // Industria alimentare
            '11' => 'food',             // Industria delle bevande
            '21' => 'manufacturing',    // Fabbricazione farmaci
            '26' => 'manufacturing',    // Fabbricazione computer e elettronica
            '27' => 'manufacturing',    // Fabbricazione apparecchiature elettriche
            '28' => 'manufacturing',    // Fabbricazione macchinari
            '29' => 'manufacturing',    // Fabbricazione autoveicoli
            '30' => 'manufacturing',    // Fabbricazione altri mezzi di trasporto
            '72' => 'research',         // Ricerca e sviluppo
            '85' => 'research',         // Istruzione
        ];

        if (isset($byCode[$code2])) {
            return $byCode[$code2];
        }

        // Fallback per keyword nella descrizione
        $byKeyword = [
            'energia'     => 'energy',
            'elettric'    => 'energy',
            'gas'         => 'energy',
            'petroli'     => 'energy',
            'idrogeno'    => 'energy',
            'trasport'    => 'transport',
            'ferrov'      => 'transport',
            'maritt'      => 'transport',
            'aereo'       => 'transport',
            'aere'        => 'transport',
            'logistic'    => 'transport',
            'banc'        => 'banking',
            'finanz'      => 'banking',
            'assicur'     => 'banking',
            'sanit'       => 'health',
            'osped'       => 'health',
            'clinic'      => 'health',
            'medic'       => 'health',
            'acqua'       => 'water',
            'idric'       => 'water',
            'rifiut'      => 'waste',
            'smaltim'     => 'waste',
            'telecom'     => 'digital_infra',
            'teleco'      => 'digital_infra',
            'fibra'       => 'digital_infra',
            'internet'    => 'digital_infra',
            'informatica' => 'ict_services',
            'software'    => 'ict_services',
            'cloud'       => 'ict_services',
            'digital'     => 'digital_providers',
            'piattaform'  => 'digital_providers',
            'postale'     => 'postal',
            'corriere'    => 'postal',
            'spediz'      => 'postal',
            'chimic'      => 'chemical',
            'farmac'      => 'manufacturing',
            'alimentar'   => 'food',
            'bevand'      => 'food',
            'ricerca'     => 'research',
            'spazial'     => 'space',
            'aerospaz'    => 'space',
            'manifattur'  => 'manufacturing',
        ];

        foreach ($byKeyword as $kw => $sector) {
            if (str_contains($desc, $kw)) {
                return $sector;
            }
        }

        return null;
    }

    // ─────────────────────────────────────────────────────────────────────────
    // METODI PRIVATI — Claude AI
    // ─────────────────────────────────────────────────────────────────────────

    private function callClaudeApi(array $content): ?string
    {
        $payload = [
            'model'      => ANTHROPIC_MODEL,
            'max_tokens' => ANTHROPIC_MAX_TOKENS,
            'messages'   => [['role' => 'user', 'content' => $content]],
        ];

        $ch = curl_init('https://api.anthropic.com/v1/messages');
        curl_setopt_array($ch, [
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => json_encode($payload),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 60,
            CURLOPT_HTTPHEADER     => [
                'Content-Type: application/json',
                'x-api-key: ' . ANTHROPIC_API_KEY,
                'anthropic-version: 2023-06-01',
            ],
        ]);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error    = curl_error($ch);
        unset($ch);

        if ($error) throw new RuntimeException('Claude API error: ' . $error);
        if ($httpCode !== 200) {
            error_log('[CLAUDE_API_ERROR] HTTP ' . $httpCode . ': ' . $response);
            throw new RuntimeException('Claude API returned HTTP ' . $httpCode);
        }

        $result = json_decode($response, true);
        return $result['content'][0]['text'] ?? null;
    }

    private function logAiInteraction(string $type, string $summary): void
    {
        try {
            $userId = null;
            $token  = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
            if (preg_match('/Bearer\s+(.+)$/i', $token, $m)) {
                $parts = explode('.', $m[1]);
                if (count($parts) === 3) {
                    $pl     = json_decode(base64_decode(strtr($parts[1], '-_', '+/')), true);
                    $userId = $pl['sub'] ?? null;
                }
            }
            if ($userId) {
                Database::insert('ai_interactions', [
                    'organization_id'  => 0,
                    'user_id'          => $userId,
                    'interaction_type' => $type,
                    'prompt_summary'   => $summary,
                    'response_summary' => 'Dati estratti',
                    'tokens_used'      => 0,
                    'model_used'       => ANTHROPIC_MODEL,
                ]);
            }
        } catch (Throwable $e) {
            error_log('[AI_LOG_ERROR] ' . $e->getMessage());
        }
    }
}
