<?php
/**
 * NIS2 Agile - Non-Conformity & CAPA Controller
 *
 * Gestione non conformità e azioni correttive/preventive.
 * Predisposizione integrazione SistemiG.agile.
 */

require_once __DIR__ . '/BaseController.php';

class NonConformityController extends BaseController
{
    // ═══════════════════════════════════════════════════════════════════════
    // NCR CRUD
    // ═══════════════════════════════════════════════════════════════════════

    /**
     * POST /api/ncr/create
     */
    public function create(): void
    {
        $this->requireOrgRole(['org_admin', 'compliance_manager', 'auditor']);
        $this->validateRequired(['title', 'source']);

        $orgId = $this->getCurrentOrgId();
        $ncrCode = $this->generateCode('NCR');

        $ncrId = Database::insert('non_conformities', [
            'organization_id'    => $orgId,
            'ncr_code'           => $ncrCode,
            'title'              => trim($this->getParam('title')),
            'description'        => $this->getParam('description'),
            'source'             => $this->getParam('source'),
            'source_entity_type' => $this->getParam('source_entity_type'),
            'source_entity_id'   => $this->getParam('source_entity_id'),
            'severity'           => $this->getParam('severity', 'minor'),
            'category'           => $this->getParam('category'),
            'nis2_article'       => $this->getParam('nis2_article'),
            'identified_by'      => $this->getCurrentUserId(),
            'assigned_to'        => $this->getParam('assigned_to'),
            'target_close_date'  => $this->getParam('target_close_date'),
        ]);

        $this->logAudit('ncr_created', 'non_conformity', $ncrId, [
            'ncr_code' => $ncrCode,
            'source'   => $this->getParam('source'),
        ]);

        $this->jsonSuccess([
            'id'       => $ncrId,
            'ncr_code' => $ncrCode,
        ], 'Non conformita\' creata', 201);
    }

    /**
     * GET /api/ncr/list
     */
    public function list(): void
    {
        $this->requireOrgAccess();
        $orgId = $this->getCurrentOrgId();

        $pagination = $this->getPagination();
        $page = $pagination['page'];
        $perPage = $pagination['per_page'];
        $offset = $pagination['offset'];

        // Filters
        $where = 'n.organization_id = ?';
        $params = [$orgId];

        $status = $this->getParam('status');
        if ($status) {
            $where .= ' AND n.status = ?';
            $params[] = $status;
        }

        $severity = $this->getParam('severity');
        if ($severity) {
            $where .= ' AND n.severity = ?';
            $params[] = $severity;
        }

        $source = $this->getParam('source');
        if ($source) {
            $where .= ' AND n.source = ?';
            $params[] = $source;
        }

        $total = Database::count('non_conformities n', $where, $params);

        $ncrs = Database::fetchAll(
            "SELECT n.*, u1.full_name as identified_by_name, u2.full_name as assigned_to_name,
                    (SELECT COUNT(*) FROM capa_actions WHERE ncr_id = n.id) as capa_count
             FROM non_conformities n
             LEFT JOIN users u1 ON u1.id = n.identified_by
             LEFT JOIN users u2 ON u2.id = n.assigned_to
             WHERE {$where}
             ORDER BY n.created_at DESC
             LIMIT {$perPage} OFFSET {$offset}",
            $params
        );

        $this->jsonPaginated($ncrs, $total, $page, $perPage);
    }

    /**
     * GET /api/ncr/{id}
     */
    public function get(int $id): void
    {
        $this->requireOrgAccess();

        $ncr = Database::fetchOne(
            'SELECT n.*, u1.full_name as identified_by_name, u2.full_name as assigned_to_name
             FROM non_conformities n
             LEFT JOIN users u1 ON u1.id = n.identified_by
             LEFT JOIN users u2 ON u2.id = n.assigned_to
             WHERE n.id = ? AND n.organization_id = ?',
            [$id, $this->getCurrentOrgId()]
        );

        if (!$ncr) {
            $this->jsonError('Non conformita\' non trovata', 404, 'NCR_NOT_FOUND');
        }

        // Load CAPA actions
        $ncr['capa_actions'] = Database::fetchAll(
            'SELECT ca.*, u1.full_name as responsible_name, u2.full_name as verified_by_name
             FROM capa_actions ca
             LEFT JOIN users u1 ON u1.id = ca.responsible_user_id
             LEFT JOIN users u2 ON u2.id = ca.verified_by
             WHERE ca.ncr_id = ?
             ORDER BY ca.created_at ASC',
            [$id]
        );

        $this->jsonSuccess($ncr);
    }

    /**
     * PUT /api/ncr/{id}
     */
    public function update(int $id): void
    {
        $this->requireOrgRole(['org_admin', 'compliance_manager', 'auditor']);

        $ncr = Database::fetchOne(
            'SELECT id FROM non_conformities WHERE id = ? AND organization_id = ?',
            [$id, $this->getCurrentOrgId()]
        );

        if (!$ncr) {
            $this->jsonError('Non conformita\' non trovata', 404, 'NCR_NOT_FOUND');
        }

        $allowedFields = [
            'title', 'description', 'severity', 'category', 'nis2_article',
            'status', 'assigned_to', 'target_close_date', 'actual_close_date',
            'root_cause_analysis', 'root_cause_method',
        ];

        $updates = [];
        foreach ($allowedFields as $field) {
            if ($this->hasParam($field)) {
                $updates[$field] = $this->getParam($field);
            }
        }

        if (empty($updates)) {
            $this->jsonError('Nessun campo da aggiornare', 400, 'NO_UPDATES');
        }

        // Auto-set close date when status becomes closed
        if (isset($updates['status']) && $updates['status'] === 'closed' && !isset($updates['actual_close_date'])) {
            $updates['actual_close_date'] = date('Y-m-d');
        }

        Database::update('non_conformities', $updates, 'id = ?', [$id]);

        $this->logAudit('ncr_updated', 'non_conformity', $id, $updates);

        $this->jsonSuccess($updates, 'Non conformita\' aggiornata');
    }

    // ═══════════════════════════════════════════════════════════════════════
    // CAPA ACTIONS
    // ═══════════════════════════════════════════════════════════════════════

    /**
     * POST /api/ncr/{id}/capa
     */
    public function addCapa(int $ncrId): void
    {
        $this->requireOrgRole(['org_admin', 'compliance_manager', 'auditor']);
        $this->validateRequired(['title', 'action_type']);

        $orgId = $this->getCurrentOrgId();

        // Verify NCR belongs to org
        $ncr = Database::fetchOne(
            'SELECT id FROM non_conformities WHERE id = ? AND organization_id = ?',
            [$ncrId, $orgId]
        );

        if (!$ncr) {
            $this->jsonError('Non conformita\' non trovata', 404, 'NCR_NOT_FOUND');
        }

        $capaCode = $this->generateCode('CAPA');

        $capaId = Database::insert('capa_actions', [
            'ncr_id'              => $ncrId,
            'organization_id'     => $orgId,
            'capa_code'           => $capaCode,
            'action_type'         => $this->getParam('action_type', 'corrective'),
            'title'               => trim($this->getParam('title')),
            'description'         => $this->getParam('description'),
            'responsible_user_id' => $this->getParam('responsible_user_id'),
            'due_date'            => $this->getParam('due_date'),
            'notes'               => $this->getParam('notes'),
        ]);

        // Update NCR status to action_planned if still open/investigating
        $ncrStatus = Database::fetchOne('SELECT status FROM non_conformities WHERE id = ?', [$ncrId]);
        if ($ncrStatus && in_array($ncrStatus['status'], ['open', 'investigating'])) {
            Database::update('non_conformities', ['status' => 'action_planned'], 'id = ?', [$ncrId]);
        }

        $this->logAudit('capa_created', 'capa_action', $capaId, [
            'ncr_id'    => $ncrId,
            'capa_code' => $capaCode,
        ]);

        $this->jsonSuccess([
            'id'        => $capaId,
            'capa_code' => $capaCode,
        ], 'Azione CAPA creata', 201);
    }

    /**
     * PUT /api/ncr/capa/{subId}
     */
    public function updateCapa(int $capaId): void
    {
        $this->requireOrgRole(['org_admin', 'compliance_manager', 'auditor']);

        $capa = Database::fetchOne(
            'SELECT id, ncr_id FROM capa_actions WHERE id = ? AND organization_id = ?',
            [$capaId, $this->getCurrentOrgId()]
        );

        if (!$capa) {
            $this->jsonError('Azione CAPA non trovata', 404, 'CAPA_NOT_FOUND');
        }

        $allowedFields = [
            'title', 'description', 'action_type', 'status',
            'responsible_user_id', 'due_date', 'completion_date',
            'verification_date', 'verified_by', 'effectiveness_review',
            'is_effective', 'notes',
        ];

        $updates = [];
        foreach ($allowedFields as $field) {
            if ($this->hasParam($field)) {
                $updates[$field] = $this->getParam($field);
            }
        }

        if (empty($updates)) {
            $this->jsonError('Nessun campo da aggiornare', 400, 'NO_UPDATES');
        }

        // Auto-set completion date
        if (isset($updates['status']) && $updates['status'] === 'completed' && !isset($updates['completion_date'])) {
            $updates['completion_date'] = date('Y-m-d');
        }

        Database::update('capa_actions', $updates, 'id = ?', [$capaId]);

        $this->logAudit('capa_updated', 'capa_action', $capaId, $updates);

        $this->jsonSuccess($updates, 'Azione CAPA aggiornata');
    }

    // ═══════════════════════════════════════════════════════════════════════
    // BULK CREATE FROM ASSESSMENT
    // ═══════════════════════════════════════════════════════════════════════

    /**
     * POST /api/ncr/fromAssessment
     * Genera NCR dai gap (risposte not_implemented/partial) di un assessment
     */
    public function fromAssessment(): void
    {
        $this->requireOrgRole(['org_admin', 'compliance_manager']);
        $this->validateRequired(['assessment_id']);

        $orgId = $this->getCurrentOrgId();
        $assessmentId = (int) $this->getParam('assessment_id');

        // Verify assessment belongs to org
        $assessment = Database::fetchOne(
            'SELECT id, title FROM assessments WHERE id = ? AND organization_id = ?',
            [$assessmentId, $orgId]
        );

        if (!$assessment) {
            $this->jsonError('Assessment non trovato', 404, 'ASSESSMENT_NOT_FOUND');
        }

        // Check for existing NCRs from this assessment to avoid duplicates
        $existingCount = Database::count(
            'non_conformities',
            'organization_id = ? AND source = ? AND source_entity_type = ? AND source_entity_id IN (SELECT id FROM assessment_responses WHERE assessment_id = ?)',
            [$orgId, 'assessment', 'assessment_response', $assessmentId]
        );

        if ($existingCount > 0) {
            $this->jsonError(
                "Esistono gia' {$existingCount} non conformita' generate da questo assessment",
                409,
                'NCR_ALREADY_GENERATED'
            );
        }

        // Find gaps
        $gaps = Database::fetchAll(
            'SELECT * FROM assessment_responses
             WHERE assessment_id = ?
             AND response_value IN ("not_implemented", "partial")
             ORDER BY category, question_code',
            [$assessmentId]
        );

        if (empty($gaps)) {
            $this->jsonSuccess(['created' => [], 'total' => 0], 'Nessun gap trovato nell\'assessment');
            return;
        }

        $created = [];
        $assessmentTitle = $assessment['title'];

        foreach ($gaps as $gap) {
            $severity = $gap['response_value'] === 'not_implemented' ? 'major' : 'minor';
            $ncrCode = $this->generateCode('NCR');

            $questionText = $gap['question_text'] ?? '';
            $title = mb_strlen($questionText) > 200
                ? 'Gap: ' . mb_substr($questionText, 0, 197) . '...'
                : 'Gap: ' . $questionText;

            $ncrId = Database::insert('non_conformities', [
                'organization_id'    => $orgId,
                'ncr_code'           => $ncrCode,
                'title'              => $title,
                'description'        => "Gap identificato nell'assessment \"{$assessmentTitle}\": {$questionText}",
                'source'             => 'assessment',
                'source_entity_type' => 'assessment_response',
                'source_entity_id'   => $gap['id'],
                'severity'           => $severity,
                'category'           => $gap['category'] ?? null,
                'nis2_article'       => $gap['nis2_article'] ?? null,
                'identified_by'      => $this->getCurrentUserId(),
                'status'             => 'open',
            ]);

            $created[] = [
                'id'       => $ncrId,
                'ncr_code' => $ncrCode,
                'severity' => $severity,
                'category' => $gap['category'] ?? null,
            ];
        }

        $this->logAudit('ncr_bulk_created', 'assessment', $assessmentId, [
            'count' => count($created),
        ]);

        $this->jsonSuccess([
            'created' => $created,
            'total'   => count($created),
        ], count($created) . ' non conformita\' generate dall\'assessment');
    }

    // ═══════════════════════════════════════════════════════════════════════
    // STATISTICS
    // ═══════════════════════════════════════════════════════════════════════

    /**
     * GET /api/ncr/stats
     */
    public function stats(): void
    {
        $this->requireOrgAccess();
        $orgId = $this->getCurrentOrgId();

        // NCR counts by status
        $byStatus = Database::fetchAll(
            'SELECT status, COUNT(*) as count FROM non_conformities WHERE organization_id = ? GROUP BY status',
            [$orgId]
        );

        // NCR counts by severity
        $bySeverity = Database::fetchAll(
            'SELECT severity, COUNT(*) as count FROM non_conformities WHERE organization_id = ? GROUP BY severity',
            [$orgId]
        );

        // CAPA counts by status
        $capaByStatus = Database::fetchAll(
            'SELECT status, COUNT(*) as count FROM capa_actions WHERE organization_id = ? GROUP BY status',
            [$orgId]
        );

        // Overdue NCRs
        $overdueNcr = Database::count(
            'non_conformities',
            'organization_id = ? AND target_close_date < CURDATE() AND status NOT IN ("closed", "cancelled")',
            [$orgId]
        );

        // Overdue CAPAs
        $overdueCapa = Database::count(
            'capa_actions',
            'organization_id = ? AND due_date < CURDATE() AND status NOT IN ("completed", "verified")',
            [$orgId]
        );

        $totalNcr = Database::count('non_conformities', 'organization_id = ?', [$orgId]);
        $openNcr = Database::count('non_conformities', 'organization_id = ? AND status NOT IN ("closed", "cancelled")', [$orgId]);

        $this->jsonSuccess([
            'total_ncr'       => $totalNcr,
            'open_ncr'        => $openNcr,
            'overdue_ncr'     => $overdueNcr,
            'overdue_capa'    => $overdueCapa,
            'ncr_by_status'   => $byStatus,
            'ncr_by_severity' => $bySeverity,
            'capa_by_status'  => $capaByStatus,
        ]);
    }

    // ═══════════════════════════════════════════════════════════════════════
    // EXTERNAL INTEGRATION (SistemiG.agile - Future)
    // ═══════════════════════════════════════════════════════════════════════

    /**
     * POST /api/ncr/{id}/sync
     * Sincronizza NCR con sistema esterno (SistemiG.agile)
     */
    public function syncExternal(int $id): void
    {
        $this->requireOrgRole(['org_admin', 'compliance_manager']);

        $ncr = Database::fetchOne(
            'SELECT * FROM non_conformities WHERE id = ? AND organization_id = ?',
            [$id, $this->getCurrentOrgId()]
        );

        if (!$ncr) {
            $this->jsonError('Non conformita\' non trovata', 404, 'NCR_NOT_FOUND');
        }

        $targetUrl = defined('SISTEMIG_API_URL') ? SISTEMIG_API_URL : '';
        if (empty($targetUrl)) {
            $this->jsonError('Integrazione SistemiG non configurata', 501, 'INTEGRATION_NOT_CONFIGURED');
        }

        // Placeholder: in future this will POST to SistemiG API
        $this->jsonSuccess([
            'ncr_id'     => $id,
            'ncr_code'   => $ncr['ncr_code'],
            'sync_status' => 'not_implemented',
            'message'    => 'Integrazione SistemiG.agile in fase di sviluppo',
        ]);
    }

    /**
     * POST /api/ncr/webhook
     * Webhook per ricezione aggiornamenti da sistema esterno
     * Autenticato via API key (X-SistemiG-Key header), non JWT
     */
    public function webhook(): void
    {
        // Authenticate via API key instead of JWT
        $apiKey = $_SERVER['HTTP_X_SISTEMIG_KEY'] ?? '';
        $expectedKey = defined('SISTEMIG_API_KEY') ? SISTEMIG_API_KEY : '';

        if (empty($expectedKey) || $apiKey !== $expectedKey) {
            $this->jsonError('Chiave API non valida', 401, 'INVALID_API_KEY');
        }

        // Placeholder: process incoming webhook payload
        $payload = $this->getJsonBody();

        $this->jsonSuccess([
            'received'   => true,
            'message'    => 'Webhook ricevuto. Integrazione SistemiG.agile in fase di sviluppo.',
            'payload_keys' => array_keys($payload),
        ]);
    }
}
