<?php
/**
 * NIS2 Agile - Front Controller / Router
 *
 * Tutte le richieste API passano da qui.
 * URL Pattern: /api/{controller}/{action}/{id?}
 */

// ═══════════════════════════════════════════════════════════════════════════
// BOOTSTRAP
// ═══════════════════════════════════════════════════════════════════════════
require_once __DIR__ . '/../application/config/config.php';
require_once __DIR__ . '/../application/config/database.php';

// ═══════════════════════════════════════════════════════════════════════════
// CORS HEADERS
// ═══════════════════════════════════════════════════════════════════════════
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';

if (in_array($origin, CORS_ALLOWED_ORIGINS)) {
    header("Access-Control-Allow-Origin: {$origin}");
}
// NOTE: No wildcard CORS even in debug mode — use CORS_ALLOWED_ORIGINS in config

header("Access-Control-Allow-Methods: " . CORS_ALLOWED_METHODS);
header("Access-Control-Allow-Headers: " . CORS_ALLOWED_HEADERS);
header("Access-Control-Max-Age: " . CORS_MAX_AGE);

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204);
    exit;
}

// ═══════════════════════════════════════════════════════════════════════════
// ROUTING
// ═══════════════════════════════════════════════════════════════════════════

$requestUri = $_SERVER['REQUEST_URI'] ?? '/';
$basePath = '';

$path = parse_url($requestUri, PHP_URL_PATH);
$path = preg_replace("#^{$basePath}#", '', $path);
$path = trim($path, '/');

// Se non è una richiesta API, servi file statici o index.html
if (!preg_match('#^api/#', $path)) {
    $staticFile = __DIR__ . '/' . $path;
    if ($path && file_exists($staticFile) && is_file($staticFile)) {
        return false;
    }

    if (empty($path) || $path === 'index.html') {
        include __DIR__ . '/index.html';
        exit;
    }

    // Prova a servire come HTML page
    $htmlFile = __DIR__ . '/' . $path;
    if (!str_ends_with($path, '.html')) {
        $htmlFile = __DIR__ . '/' . $path . '.html';
    }
    if (file_exists($htmlFile) && is_file($htmlFile)) {
        include $htmlFile;
        exit;
    }

    http_response_code(404);
    echo json_encode(['success' => false, 'message' => 'Not Found']);
    exit;
}

// ═══════════════════════════════════════════════════════════════════════════
// API ROUTING
// ═══════════════════════════════════════════════════════════════════════════

$parts = explode('/', $path);
array_shift($parts); // Rimuovi "api"

$controllerName = $parts[0] ?? 'index';
$actionName = $parts[1] ?? 'index';
$resourceId = isset($parts[2]) ? $parts[2] : null;
$subAction = $parts[3] ?? null;
$subResourceId = isset($parts[4]) ? $parts[4] : null;

// Mappa controller
$controllerMap = [
    'auth'          => 'AuthController',
    'organizations' => 'OrganizationController',
    'assessments'   => 'AssessmentController',
    'dashboard'     => 'DashboardController',
    'risks'         => 'RiskController',
    'incidents'     => 'IncidentController',
    'policies'      => 'PolicyController',
    'supply-chain'  => 'SupplyChainController',
    'training'      => 'TrainingController',
    'assets'        => 'AssetController',
    'audit'         => 'AuditController',
    'admin'         => 'AdminController',
    'onboarding'    => 'OnboardingController',
    'ncr'           => 'NonConformityController',
    'services'      => 'ServicesController',
    'invites'       => 'InviteController',
    'webhooks'      => 'WebhookController',
    'whistleblowing'=> 'WhistleblowingController',
    'normative'       => 'NormativeController',
    'cross-analysis'  => 'CrossAnalysisController',
    'contact'         => 'ContactController',   // legacy
    'mktg-lead'       => 'MktgLeadController',  // standard condiviso TRPG/NIS2
    'feedback'        => 'FeedbackController',  // segnalazioni & risoluzione AI
];

if (!isset($controllerMap[$controllerName])) {
    http_response_code(404);
    header('Content-Type: application/json');
    echo json_encode([
        'success' => false,
        'message' => 'Endpoint non trovato',
        'error_code' => 'NOT_FOUND',
    ]);
    exit;
}

$controllerClass = $controllerMap[$controllerName];
$controllerFile = APP_PATH . "/controllers/{$controllerClass}.php";

if (!file_exists($controllerFile)) {
    http_response_code(500);
    header('Content-Type: application/json');
    echo json_encode([
        'success' => false,
        'message' => 'Controller non disponibile',
    ]);
    exit;
}

require_once $controllerFile;

// ═══════════════════════════════════════════════════════════════════════════
// MAPPA AZIONI PER METODO HTTP
// ═══════════════════════════════════════════════════════════════════════════
$method = $_SERVER['REQUEST_METHOD'];

// Converti action name con trattini in camelCase
$actionName = str_replace('-', '', lcfirst(ucwords($actionName, '-')));

$actionMap = [
    // ── AuthController ──────────────────────────────
    'auth' => [
        'POST:register'        => 'register',
        'POST:login'           => 'login',
        'POST:logout'          => 'logout',
        'POST:refresh'         => 'refresh',
        'GET:me'               => 'me',
        'PUT:profile'          => 'updateProfile',
        'POST:changePassword'  => 'changePassword',
        'POST:validateInvite'  => 'validateInvite',  // valida invite_token (no auth)
    ],

    // ── OrganizationController ──────────────────────
    'organizations' => [
        'POST:create'                          => 'create',
        'GET:current'                          => 'getCurrent',
        'GET:list'                             => 'list',
        'PUT:{id}'                             => 'update',
        'GET:{id}/members'                     => 'listMembers',
        'POST:{id}/invite'                     => 'inviteMember',
        'DELETE:{id}/members/{subId}'          => 'removeMember',
        'POST:classify'                        => 'classifyEntity',
    ],

    // ── AssessmentController ────────────────────────
    'assessments' => [
        'GET:list'                  => 'list',
        'POST:create'               => 'create',
        'GET:{id}'                  => 'get',
        'PUT:{id}'                  => 'update',
        'GET:{id}/questions'        => 'getQuestions',
        'POST:{id}/respond'         => 'saveResponse',
        'POST:{id}/complete'        => 'complete',
        'GET:{id}/report'           => 'getReport',
        'POST:{id}/aiAnalyze'       => 'aiAnalyze',
    ],

    // ── DashboardController ─────────────────────────
    'dashboard' => [
        'GET:overview'             => 'overview',
        'GET:complianceScore'      => 'complianceScore',
        'GET:upcomingDeadlines'    => 'deadlines',
        'GET:recentActivity'       => 'recentActivity',
        'GET:riskHeatmap'          => 'riskHeatmap',
    ],

    // ── RiskController ──────────────────────────────
    'risks' => [
        'GET:list'                  => 'list',
        'POST:create'               => 'create',
        'GET:{id}'                  => 'get',
        'PUT:{id}'                  => 'update',
        'DELETE:{id}'               => 'delete',
        'POST:{id}/treatments'      => 'addTreatment',
        'PUT:treatments/{subId}'    => 'updateTreatment',
        'GET:matrix'                => 'getRiskMatrix',
        'POST:aiSuggest'            => 'aiSuggestRisks',
    ],

    // ── IncidentController ──────────────────────────
    'incidents' => [
        'GET:list'                        => 'list',
        'POST:create'                     => 'create',
        'GET:{id}'                        => 'get',
        'PUT:{id}'                        => 'update',
        'POST:{id}/timeline'              => 'addTimelineEvent',
        'POST:{id}/earlyWarning'          => 'sendEarlyWarning',
        'POST:{id}/notification'          => 'sendNotification',
        'POST:{id}/finalReport'           => 'sendFinalReport',
        'POST:{id}/aiClassify'            => 'aiClassify',
    ],

    // ── PolicyController ────────────────────────────
    'policies' => [
        'GET:list'                  => 'list',
        'POST:create'               => 'create',
        'GET:{id}'                  => 'get',
        'PUT:{id}'                  => 'update',
        'DELETE:{id}'               => 'delete',
        'POST:{id}/approve'         => 'approve',
        'POST:aiGenerate'           => 'aiGeneratePolicy',
        'GET:templates'             => 'getTemplates',
    ],

    // ── SupplyChainController ───────────────────────
    'supply-chain' => [
        'GET:list'                  => 'list',
        'POST:create'               => 'create',
        'GET:{id}'                  => 'get',
        'PUT:{id}'                  => 'update',
        'DELETE:{id}'               => 'delete',
        'POST:{id}/assess'          => 'assessSupplier',
        'GET:riskOverview'          => 'riskOverview',
    ],

    // ── TrainingController ──────────────────────────
    'training' => [
        'GET:courses'               => 'listCourses',
        'POST:courses'              => 'createCourse',
        'GET:assignments'           => 'myAssignments',
        'POST:assign'               => 'assignCourse',
        'PUT:assignments/{subId}'   => 'updateAssignment',
        'GET:complianceStatus'      => 'complianceStatus',
    ],

    // ── AssetController ─────────────────────────────
    'assets' => [
        'GET:list'                  => 'list',
        'POST:create'               => 'create',
        'GET:{id}'                  => 'get',
        'PUT:{id}'                  => 'update',
        'DELETE:{id}'               => 'delete',
        'GET:dependencyMap'         => 'dependencyMap',
    ],

    // ── AuditController ─────────────────────────────
    'audit' => [
        'GET:controls'              => 'listControls',
        'PUT:controls/{subId}'      => 'updateControl',
        'POST:evidence/upload'      => 'uploadEvidence',
        'GET:evidence/list'         => 'listEvidence',
        'GET:report'                => 'generateReport',
        'GET:logs'                  => 'getAuditLogs',
        'GET:iso27001Mapping'       => 'getIsoMapping',
        'GET:executiveReport'       => 'executiveReport',
        'GET:export'                => 'export',
        'GET:chainVerify'           => 'chainVerify',
        'GET:exportCertified'       => 'exportCertified',
    ],

    // ── AdminController ─────────────────────────────
    'admin' => [
        'GET:organizations'         => 'listOrganizations',
        'GET:users'                 => 'listUsers',
        'GET:stats'                 => 'platformStats',
    ],

    // ── OnboardingController ──────────────────────
    'onboarding' => [
        'POST:uploadVisura'  => 'uploadVisura',
        'POST:fetchCompany'  => 'fetchCompany',
        'POST:lookupPiva'    => 'lookupPiva',    // lookup P.IVA pubblico (no auth, da register)
        'POST:complete'      => 'complete',
    ],

    // ── NonConformityController (NCR & CAPA) ───────
    'ncr' => [
        'POST:create'                => 'create',
        'GET:list'                   => 'list',
        'GET:{id}'                   => 'get',
        'PUT:{id}'                   => 'update',
        'POST:{id}/capa'             => 'addCapa',
        'PUT:capa/{subId}'           => 'updateCapa',
        'POST:fromAssessment'        => 'fromAssessment',
        'GET:stats'                  => 'stats',
        'POST:{id}/sync'             => 'syncExternal',
        'POST:webhook'               => 'webhook',
    ],

    // ── InviteController (licenze/inviti B2B) ──────
    'invites' => [
        'POST:create'               => 'create',
        'GET:index'                 => 'index',
        'GET:list'                  => 'index',
        'GET:{id}'                  => 'show',
        'DELETE:{id}'               => 'revoke',
        'POST:{id}/regenerate'      => 'regenerate',
        'GET:validate'              => 'validate',  // ?token=inv_...
    ],

    // ── ServicesController (API pubblica) ──────────
    'services' => [
        'POST:provision'             => 'provision',
        'POST:token'                 => 'token',
        'POST:sso'                   => 'sso',
        'GET:status'                 => 'status',
        'GET:complianceSummary'      => 'complianceSummary',
        'GET:risksFeed'              => 'risksFeed',
        'GET:incidentsFeed'          => 'incidentsFeed',
        'GET:controlsStatus'         => 'controlsStatus',
        'GET:assetsCritical'         => 'assetsCritical',
        'GET:suppliersRisk'          => 'suppliersRisk',
        'GET:policiesApproved'       => 'policiesApproved',
        'GET:openapi'                => 'openapi',
        // lg231 / GRC integration endpoints
        'GET:gapAnalysis'            => 'gapAnalysis',
        'GET:measures'               => 'measures',
        'GET:incidents'              => 'incidents',
        'GET:training'               => 'training',
        'GET:deadlines'              => 'deadlines',
        'GET:fullSnapshot'           => 'fullSnapshot',
    ],

    // ── WebhookController (CRUD keys + subscriptions) ──
    'webhooks' => [
        'GET:apiKeys'                => 'listApiKeys',
        'POST:apiKeys'               => 'createApiKey',
        'DELETE:apiKeys/{subId}'     => 'deleteApiKey',
        'GET:subscriptions'          => 'listSubscriptions',
        'POST:subscriptions'         => 'createSubscription',
        'PUT:subscriptions/{subId}'  => 'updateSubscription',
        'DELETE:subscriptions/{subId}' => 'deleteSubscription',
        'POST:subscriptions/{subId}/test' => 'testSubscription',
        'GET:deliveries'             => 'listDeliveries',
        'POST:retry'                 => 'processRetry',
    ],

    // ── WhistleblowingController (Art.32 NIS2) ─────
    'whistleblowing' => [
        'POST:submit'                => 'submit',
        'GET:list'                   => 'list',
        'GET:{id}'                   => 'get',
        'PUT:{id}'                   => 'update',
        'POST:{id}/assign'           => 'assign',
        'POST:{id}/close'            => 'close',
        'GET:stats'                  => 'stats',
        'GET:trackAnonymous'         => 'trackAnonymous',
    ],

    // ── NormativeController (Feed NIS2/ACN) ─────────
    'normative' => [
        'GET:list'                   => 'list',
        'GET:{id}'                   => 'get',
        'POST:{id}/ack'              => 'acknowledge',
        'GET:pending'                => 'pending',
        'GET:stats'                  => 'stats',
        'POST:create'                => 'create',
    ],

    // ── CrossAnalysisController (L4 AI cross-org) ──
    'cross-analysis' => [
        'POST:analyze'               => 'analyze',
        'GET:history'                => 'history',
        'GET:portfolio'              => 'portfolio',
    ],

    // ── ContactController (lead / richiesta invito) — legacy ──
    'contact' => [
        'POST:requestInvite'         => 'requestInvite',
    ],

    // ── MktgLeadController — standard condiviso TRPG/NIS2 ──
    'mktg-lead' => [
        'POST:submit'                => 'submit',
    ],

    // ── FeedbackController — segnalazioni & risoluzione AI ──
    'feedback' => [
        'POST:submit'                => 'submit',
        'GET:mine'                   => 'mine',
        'GET:list'                   => 'list',
        'GET:{id}'                   => 'show',
        'PUT:{id}'                   => 'update',
        'POST:{id}/resolve'          => 'resolve',
    ],
];

// ═══════════════════════════════════════════════════════════════════════════
// RISOLUZIONE AZIONE
// ═══════════════════════════════════════════════════════════════════════════

$actions = $actionMap[$controllerName] ?? [];
$resolvedAction = null;
$callArgs = [];

// Helper: convert kebab-case to camelCase (same logic as $actionName conversion)
$toCamel = function (string $s): string {
    return str_replace('-', '', lcfirst(ucwords($s, '-')));
};

// Costruisci candidati pattern → argomenti (ordine: più specifico prima)
$candidates = [];

if (is_numeric($actionName)) {
    // Il primo segmento è un ID numerico:
    //   /controller/123             → METHOD:{id}
    //   /controller/123/sub         → METHOD:{id}/sub
    //   /controller/123/sub/456     → METHOD:{id}/sub/{subId}
    $numericId = (int) $actionName;
    $sub = $resourceId !== null ? $toCamel($resourceId) : null;
    $subId = $subAction !== null && is_numeric($subAction) ? (int) $subAction : null;

    if ($sub !== null && $subId !== null) {
        $candidates[] = ['p' => "{$method}:{id}/{$sub}/{subId}", 'a' => [$numericId, $subId]];
    }
    if ($sub !== null) {
        $candidates[] = ['p' => "{$method}:{id}/{$sub}", 'a' => [$numericId]];
    }
    $candidates[] = ['p' => "{$method}:{id}", 'a' => [$numericId]];

} else {
    // Il primo segmento è un'azione nominale:
    //   /controller/action                → METHOD:action
    //   /controller/action/123            → METHOD:action/{subId}  oppure  METHOD:{id}
    //   /controller/action/sub            → METHOD:action/sub
    //   /controller/action/123/sub        → METHOD:{id}/sub
    //   /controller/action/123/sub/456    → METHOD:{id}/sub/{subId}

    if ($subAction !== null && $resourceId !== null && is_numeric($resourceId)) {
        $rid = (int) $resourceId;
        $camelSub = $toCamel($subAction);

        if ($subResourceId !== null && is_numeric($subResourceId)) {
            $sid = (int) $subResourceId;
            $candidates[] = ['p' => "{$method}:{id}/{$camelSub}/{subId}", 'a' => [$rid, $sid]];
        }
        // e.g. POST:subscriptions/{subId}/test
        $candidates[] = ['p' => "{$method}:{$actionName}/{subId}/{$camelSub}", 'a' => [$rid]];
        $candidates[] = ['p' => "{$method}:{id}/{$camelSub}", 'a' => [$rid]];
        $candidates[] = ['p' => "{$method}:{$actionName}/{subId}", 'a' => [$rid]];
    }

    if ($resourceId !== null && $subAction === null) {
        if (is_numeric($resourceId)) {
            // /controller/action/123 → potrebbe essere action/{subId} o {id}
            $rid = (int) $resourceId;
            $candidates[] = ['p' => "{$method}:{$actionName}/{subId}", 'a' => [$rid]];
            $candidates[] = ['p' => "{$method}:{id}", 'a' => [$rid]];
        } else {
            // /controller/action/subAction → nome composto (es: evidence/upload)
            $camelResource = $toCamel($resourceId);
            $candidates[] = ['p' => "{$method}:{$actionName}/{$camelResource}", 'a' => []];
        }
    }

    // /controller/action
    $candidates[] = ['p' => "{$method}:{$actionName}", 'a' => []];
}

// Cerca primo match
foreach ($candidates as $candidate) {
    if (isset($actions[$candidate['p']])) {
        $resolvedAction = $actions[$candidate['p']];
        $callArgs = $candidate['a'];
        break;
    }
}

if (!$resolvedAction) {
    http_response_code(404);
    header('Content-Type: application/json');
    echo json_encode([
        'success'    => false,
        'message'    => "Azione non trovata: {$method} /{$controllerName}/{$actionName}",
        'error_code' => 'ACTION_NOT_FOUND',
    ]);
    exit;
}

// ═══════════════════════════════════════════════════════════════════════════
// ESECUZIONE
// ═══════════════════════════════════════════════════════════════════════════

try {
    $controller = new $controllerClass();

    if (!method_exists($controller, $resolvedAction)) {
        http_response_code(501);
        header('Content-Type: application/json');
        echo json_encode([
            'success' => false,
            'message' => "Metodo '{$resolvedAction}' non implementato",
        ]);
        exit;
    }

    // Chiama con gli argomenti risolti
    $controller->$resolvedAction(...$callArgs);
} catch (RuntimeException $e) {
    // Rate limit exceeded (429)
    if ($e->getCode() === 429) {
        http_response_code(429);
        header('Content-Type: application/json');
        echo json_encode([
            'success' => false,
            'message' => $e->getMessage(),
            'error_code' => 'RATE_LIMITED',
        ]);
        exit;
    }
    throw $e;
} catch (PDOException $e) {
    error_log('[DB_ERROR] ' . $e->getMessage());
    http_response_code(500);
    header('Content-Type: application/json');
    echo json_encode([
        'success' => false,
        'message' => APP_DEBUG ? 'Errore database: ' . $e->getMessage() : 'Errore interno del server',
    ]);
} catch (Throwable $e) {
    error_log('[ERROR] ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine());
    http_response_code(500);
    header('Content-Type: application/json');
    echo json_encode([
        'success' => false,
        'message' => APP_DEBUG ? $e->getMessage() : 'Errore interno del server',
    ]);
}
