<?php
/**
 * NIS2 Agile - Onboarding Controller
 *
 * Gestisce il wizard di onboarding: upload visura, fetch CertiSource, completamento.
 */

require_once __DIR__ . '/BaseController.php';
require_once __DIR__ . '/../services/VisuraService.php';
require_once APP_PATH . '/services/RateLimitService.php';

class OnboardingController extends BaseController
{
    /**
     * POST /api/onboarding/upload-visura
     * Riceve PDF visura camerale, estrae dati con AI
     */
    public function uploadVisura(): void
    {
        $this->requireAuth();

        // Validate file upload
        if (!isset($_FILES['visura']) || $_FILES['visura']['error'] !== UPLOAD_ERR_OK) {
            $this->jsonError('Nessun file caricato o errore upload', 400, 'UPLOAD_ERROR');
        }

        $file = $_FILES['visura'];

        // Validate file type (PDF only)
        $allowedTypes = ['application/pdf'];
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $mimeType = finfo_file($finfo, $file['tmp_name']);
        finfo_close($finfo);

        if (!in_array($mimeType, $allowedTypes)) {
            $this->jsonError('Solo file PDF sono accettati', 400, 'INVALID_FILE_TYPE');
        }

        // Max 10MB
        if ($file['size'] > 10 * 1024 * 1024) {
            $this->jsonError('File troppo grande (max 10MB)', 400, 'FILE_TOO_LARGE');
        }

        // Save file temporarily
        $uploadDir = UPLOAD_PATH . '/visure';
        if (!is_dir($uploadDir)) {
            mkdir($uploadDir, 0755, true);
        }

        $fileName = 'visura_' . $this->getCurrentUserId() . '_' . time() . '.pdf';
        $filePath = $uploadDir . '/' . $fileName;

        if (!move_uploaded_file($file['tmp_name'], $filePath)) {
            $this->jsonError('Errore nel salvataggio del file', 500, 'SAVE_ERROR');
        }

        try {
            // Extract data using AI
            $visuraService = new VisuraService();
            $extractedData = $visuraService->extractFromPdf($filePath);

            $this->logAudit('visura_uploaded', 'onboarding', null, [
                'file' => $fileName,
                'extracted' => !empty($extractedData)
            ]);

            $this->jsonSuccess($extractedData, 'Dati estratti dalla visura');
        } catch (Throwable $e) {
            error_log('[VISURA_ERROR] ' . $e->getMessage());
            $this->jsonError(
                APP_DEBUG ? 'Errore estrazione: ' . $e->getMessage() : 'Errore nell\'analisi della visura',
                500,
                'EXTRACTION_ERROR'
            );
        }
    }

    /**
     * POST /api/onboarding/fetch-company
     * Recupera dati aziendali da CertiSource tramite P.IVA
     */
    public function fetchCompany(): void
    {
        $this->requireAuth();
        $this->validateRequired(['vat_number']);

        $vatNumber = trim($this->getParam('vat_number'));

        // Clean VAT: remove IT prefix, spaces
        $vatNumber = preg_replace('/^IT/i', '', $vatNumber);
        $vatNumber = preg_replace('/\s+/', '', $vatNumber);

        // Validate Italian P.IVA format (11 digits)
        if (!preg_match('/^\d{11}$/', $vatNumber)) {
            $this->jsonError('Formato Partita IVA non valido (11 cifre)', 400, 'INVALID_VAT');
        }

        try {
            $visuraService = new VisuraService();
            $companyData = $visuraService->fetchFromCertiSource($vatNumber);

            $this->logAudit('certisource_fetch', 'onboarding', null, [
                'vat_number' => $vatNumber,
                'found' => !empty($companyData)
            ]);

            if (empty($companyData) || empty($companyData['company_name'])) {
                $this->jsonError(
                    'Azienda non trovata per la P.IVA fornita',
                    404,
                    'COMPANY_NOT_FOUND'
                );
            }

            $this->jsonSuccess($companyData, 'Dati aziendali recuperati');
        } catch (Throwable $e) {
            error_log('[CERTISOURCE_ERROR] ' . $e->getMessage());
            $this->jsonError(
                APP_DEBUG ? 'Errore CertiSource: ' . $e->getMessage() : 'Errore nel recupero dati aziendali',
                500,
                'CERTISOURCE_ERROR'
            );
        }
    }

    /**
     * POST /api/onboarding/lookup-piva
     *
     * Lookup P.IVA pubblico senza autenticazione — usato dalla pagina register.html
     * per pre-compilare il nome azienda prima che l'utente abbia un account.
     *
     * Rate limiting soft: 10 req/min per IP (file-based).
     * Restituisce solo company_name e sector (nessun dato sensibile).
     */
    public function lookupPiva(): void
    {
        // Soft rate limiting (no auth)
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? 'unknown';
        $ip = trim(explode(',', $ip)[0]);
        RateLimitService::check("piva_lookup:{$ip}", [['max' => 10, 'window_seconds' => 60]]);
        RateLimitService::increment("piva_lookup:{$ip}");

        $vatNumber = trim($this->getParam('vat_number', ''));
        $vatNumber = preg_replace('/^IT/i', '', $vatNumber);
        $vatNumber = preg_replace('/\s+/', '', $vatNumber);

        if (!preg_match('/^\d{11}$/', $vatNumber)) {
            $this->jsonError('Formato P.IVA non valido (11 cifre)', 400, 'INVALID_VAT');
        }

        try {
            $visuraService = new VisuraService();
            $data = $visuraService->fetchFromCertiSource($vatNumber);

            if (empty($data) || empty($data['company_name'])) {
                $this->jsonError('Azienda non trovata', 404, 'COMPANY_NOT_FOUND');
            }

            // Restituisce solo i campi necessari per il pre-fill del form
            $this->jsonSuccess([
                'company_name'    => $data['company_name'],
                'sector'          => $data['sector'] ?? null,
                'nis2_entity_type'=> $data['nis2_entity_type'] ?? null,
            ], 'Azienda trovata');

        } catch (Throwable $e) {
            // CertiSource non raggiungibile o endpoint cambiato — trattato come "non trovato"
            $this->jsonError('Azienda non trovata nel registro. Inserisci i dati manualmente.', 404, 'COMPANY_NOT_FOUND');
        }
    }

    /**
     * POST /api/onboarding/complete
     * Completa l'onboarding: crea organizzazione e aggiorna profilo utente
     */
    public function complete(): void
    {
        $this->requireAuth();
        $this->validateRequired(['name', 'sector']);

        $userId = $this->getCurrentUserId();
        $currentUser = $this->getCurrentUser();
        $isConsultant = ($currentUser['role'] === 'consultant');

        // Check if user already has an organization (blocca solo per non-consulenti)
        $existingOrg = Database::fetchOne(
            'SELECT organization_id FROM user_organizations WHERE user_id = ? AND is_primary = 1',
            [$userId]
        );

        if ($existingOrg && !$isConsultant) {
            $this->jsonError('Hai già un\'organizzazione configurata', 409, 'ORG_EXISTS');
        }

        // Per consulenti: verifica che la P.IVA non sia già associata al loro account
        $vatNumber = $this->getParam('vat_number');
        if ($isConsultant && $vatNumber) {
            $cleanVat = preg_replace('/^IT/i', '', preg_replace('/\s+/', '', $vatNumber));
            $dupOrg = Database::fetchOne(
                'SELECT o.id FROM organizations o
                 JOIN user_organizations uo ON uo.organization_id = o.id
                 WHERE uo.user_id = ? AND o.vat_number = ?',
                [$userId, $cleanVat]
            );
            if ($dupOrg) {
                $this->jsonError('Questa azienda è già presente nel tuo portafoglio clienti', 409, 'ORG_DUPLICATE_VAT');
            }
        }

        Database::beginTransaction();
        try {
            // Create organization
            $orgData = [
                'name'                => trim($this->getParam('name')),
                'vat_number'          => $this->getParam('vat_number'),
                'fiscal_code'         => $this->getParam('fiscal_code'),
                'sector'              => $this->getParam('sector'),
                'employee_count'      => $this->getParam('employee_count'),
                'annual_turnover_eur' => $this->getParam('annual_turnover_eur'),
                'country'             => $this->getParam('country', 'IT'),
                'city'                => $this->getParam('city'),
                'address'             => $this->getParam('address'),
                'website'             => $this->getParam('website'),
                'contact_email'       => $this->getParam('contact_email'),
                'contact_phone'       => $this->getParam('contact_phone'),
            ];

            $orgId = Database::insert('organizations', $orgData);

            // Auto-classify NIS2 entity type
            $entityType = $this->classifyNis2Entity(
                $orgData['sector'],
                (int) ($orgData['employee_count'] ?? 0),
                (float) ($orgData['annual_turnover_eur'] ?? 0)
            );

            // Handle voluntary compliance
            $voluntaryCompliance = ($entityType === 'not_applicable' && (int) $this->getParam('voluntary_compliance', 0)) ? 1 : 0;

            Database::update('organizations', [
                'entity_type' => $entityType,
                'voluntary_compliance' => $voluntaryCompliance,
            ], 'id = ?', [$orgId]);

            // Link user: consulente → ruolo 'consultant', is_primary solo se prima org
            $orgRole = $isConsultant ? 'consultant' : 'org_admin';
            $isPrimary = $existingOrg ? 0 : 1;
            Database::insert('user_organizations', [
                'user_id'         => $userId,
                'organization_id' => $orgId,
                'role'            => $orgRole,
                'is_primary'      => $isPrimary,
            ]);

            // Update user profile if provided
            $profileUpdates = [];
            if ($this->hasParam('phone') && $this->getParam('phone')) {
                $profileUpdates['phone'] = $this->getParam('phone');
            }
            if ($this->hasParam('full_name') && $this->getParam('full_name')) {
                $profileUpdates['full_name'] = trim($this->getParam('full_name'));
            }
            if (!empty($profileUpdates)) {
                Database::update('users', $profileUpdates, 'id = ?', [$userId]);
            }

            // Initialize NIS2 compliance controls
            $this->initializeComplianceControls($orgId);

            Database::commit();

            $this->currentOrgId = $orgId;
            $this->logAudit('onboarding_completed', 'organization', $orgId, [
                'name' => $orgData['name'],
                'sector' => $orgData['sector'],
                'entity_type' => $entityType,
                'is_consultant' => $isConsultant,
            ]);

            $this->jsonSuccess([
                'organization_id'      => $orgId,
                'name'                 => $orgData['name'],
                'entity_type'          => $entityType,
                'voluntary_compliance' => $voluntaryCompliance,
                'classification'       => $this->getClassificationDetails($entityType, $orgData['sector'], (int)($orgData['employee_count'] ?? 0), (float)($orgData['annual_turnover_eur'] ?? 0)),
            ], 'Onboarding completato', 201);

        } catch (Throwable $e) {
            Database::rollback();
            throw $e;
        }
    }

    // ═══════════════════════════════════════════════════════════════════════
    // PRIVATE METHODS (copied from OrganizationController for independence)
    // ═══════════════════════════════════════════════════════════════════════

    private function classifyNis2Entity(string $sector, int $employees, float $turnover): string
    {
        // Map detailed sector codes to NIS2 categories
        $essentialSectors = [
            'energy', 'energy_electricity', 'energy_district_heating', 'energy_oil', 'energy_gas', 'energy_hydrogen',
            'transport', 'transport_air', 'transport_rail', 'transport_water', 'transport_road',
            'banking', 'financial_markets', 'health', 'water', 'drinking_water', 'waste_water',
            'digital_infra', 'digital_infrastructure', 'ict_service_management',
            'public_admin', 'public_administration', 'space',
        ];

        $importantSectors = [
            'manufacturing', 'manufacturing_medical', 'manufacturing_computers', 'manufacturing_electrical',
            'manufacturing_machinery', 'manufacturing_vehicles', 'manufacturing_transport',
            'postal', 'postal_courier', 'chemical', 'chemicals', 'food',
            'waste', 'waste_management', 'ict_services', 'digital_providers', 'research',
        ];

        $isLarge = $employees >= 250 || $turnover >= 50000000;
        $isMedium = ($employees >= 50 || $turnover >= 10000000) && !$isLarge;

        if (in_array($sector, $essentialSectors)) {
            if ($isLarge) return 'essential';
            if ($isMedium) return 'important';
        }

        if (in_array($sector, $importantSectors)) {
            if ($isLarge || $isMedium) return 'important';
        }

        return 'not_applicable';
    }

    private function getClassificationDetails(string $type, string $sector, int $employees, float $turnover): array
    {
        $sizeLabel = $employees >= 250 ? 'Grande Impresa' : ($employees >= 50 ? 'Media Impresa' : 'Piccola Impresa');

        return match ($type) {
            'essential' => [
                'type' => 'essential',
                'label' => 'Soggetto Essenziale',
                'size' => $sizeLabel,
                'description' => "La vostra organizzazione rientra tra i soggetti essenziali ai sensi della Direttiva NIS2 (UE 2022/2555). Operate in un settore ad alta criticità e superate le soglie dimensionali.",
                'obligations' => [
                    'Misure di sicurezza informatica (Art. 21)',
                    'Notifica incidenti significativi al CSIRT entro 24h/72h/30gg (Art. 23)',
                    'Formazione obbligatoria per gli organi di gestione (Art. 20)',
                    'Vigilanza proattiva (ex ante) da parte delle autorità',
                    'Sanzioni fino a EUR 10M o 2% del fatturato mondiale annuo',
                ],
            ],
            'important' => [
                'type' => 'important',
                'label' => 'Soggetto Importante',
                'size' => $sizeLabel,
                'description' => "La vostra organizzazione rientra tra i soggetti importanti ai sensi della Direttiva NIS2. Siete tenuti a rispettare gli obblighi di sicurezza e notifica incidenti.",
                'obligations' => [
                    'Misure di sicurezza informatica (Art. 21)',
                    'Notifica incidenti significativi al CSIRT entro 24h/72h/30gg (Art. 23)',
                    'Formazione obbligatoria per gli organi di gestione (Art. 20)',
                    'Vigilanza reattiva (ex post) da parte delle autorità',
                    'Sanzioni fino a EUR 7M o 1,4% del fatturato mondiale annuo',
                ],
            ],
            default => [
                'type' => 'not_applicable',
                'label' => 'Non Applicabile',
                'size' => $sizeLabel,
                'description' => "In base ai dati forniti, la vostra organizzazione non sembra rientrare nell'ambito di applicazione della Direttiva NIS2. Consigliamo comunque di adottare le best practice di cybersecurity.",
                'obligations' => [
                    'Nessun obbligo NIS2 specifico',
                    'Si raccomandano comunque buone pratiche di sicurezza informatica',
                    'Possibile designazione futura da parte delle autorità nazionali',
                ],
            ],
        };
    }

    private function initializeComplianceControls(int $orgId): void
    {
        $controls = [
            ['NIS2-21.2.a', 'nis2', 'Politiche di analisi dei rischi e sicurezza dei sistemi informatici'],
            ['NIS2-21.2.b', 'nis2', 'Gestione degli incidenti'],
            ['NIS2-21.2.c', 'nis2', 'Continuità operativa e gestione delle crisi'],
            ['NIS2-21.2.d', 'nis2', 'Sicurezza della catena di approvvigionamento'],
            ['NIS2-21.2.e', 'nis2', 'Sicurezza acquisizione, sviluppo e manutenzione sistemi'],
            ['NIS2-21.2.f', 'nis2', 'Politiche e procedure per valutare efficacia misure'],
            ['NIS2-21.2.g', 'nis2', 'Pratiche di igiene informatica di base e formazione'],
            ['NIS2-21.2.h', 'nis2', 'Politiche e procedure relative alla crittografia'],
            ['NIS2-21.2.i', 'nis2', 'Sicurezza risorse umane, controllo accessi e gestione asset'],
            ['NIS2-21.2.j', 'nis2', 'Autenticazione multi-fattore e comunicazioni sicure'],
            ['NIS2-20.1', 'nis2', 'Governance: approvazione misure da parte degli organi di gestione'],
            ['NIS2-20.2', 'nis2', 'Formazione obbligatoria per gli organi di gestione'],
            ['NIS2-23.1', 'nis2', 'Notifica incidenti significativi al CSIRT (24h/72h/30gg)'],
        ];

        foreach ($controls as [$code, $framework, $title]) {
            Database::insert('compliance_controls', [
                'organization_id' => $orgId,
                'control_code'    => $code,
                'framework'       => $framework,
                'title'           => $title,
                'status'          => 'not_started',
            ]);
        }
    }
}
