<?php

declare(strict_types=1);

// L'API doit toujours retourner du JSON pur. Les avertissements PHP ou
// espaces parasites sont capturés afin de ne jamais casser JSON.parse().
ob_start();
ini_set('display_errors', '0');
ini_set('html_errors', '0');
ini_set('log_errors', '1');

require_once __DIR__ . '/bootstrap.php';

use Install\Services\InstallationEngine;
use Install\Services\InstallationProgress;

header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store, no-cache, must-revalidate');

function respond(array $payload, int $status = 200): never
{
    if (ob_get_level() > 0) {
        ob_clean();
    }

    if (!headers_sent()) {
        header('Content-Type: application/json; charset=utf-8');
        header('Cache-Control: no-store, no-cache, must-revalidate');
    }

    http_response_code($status);

    echo json_encode(
        $payload,
        JSON_UNESCAPED_UNICODE
        | JSON_UNESCAPED_SLASHES
        | JSON_THROW_ON_ERROR
    );

    exit;
}

try {
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        respond([
            'success' => false,
            'message' => 'Méthode non autorisée.',
        ], 405);
    }

    $token = (string)($_POST['csrf_token'] ?? '');
    $sessionToken = (string)(
        $_SESSION['install_csrf_token'] ?? ''
    );

    if (
        $token === ''
        || $sessionToken === ''
        || !hash_equals($sessionToken, $token)
    ) {
        respond([
            'success' => false,
            'message' => 'Jeton de sécurité invalide.',
        ], 419);
    }

    $preparation = $_SESSION['install_preparation'] ?? null;
    $database = $_SESSION['install_database'] ?? null;

    if (
        !is_array($preparation)
        || !is_array($database)
    ) {
        respond([
            'success' => false,
            'message' => 'La préparation de l’installation a expiré.',
        ], 409);
    }

    $action = trim((string)($_POST['action'] ?? ''));
    $engine = new InstallationEngine();
    $runner = $engine->migrationRunner($database);
// P2.3.1 : MigrationRunner garantit désormais system_migrations
// avant toute lecture ou écriture.
    $progress = new InstallationProgress();

    if ($action === 'initialize') {
        $runner->resetLog();
        $progress->reset();

        $report = is_array($preparation['report'] ?? null)
            ? $preparation['report']
            : [];

        $existing = !empty(
            $report['database_state']['existing_installation']
        );

        if ($existing && !$runner->hasMigrationHistory()) {
            $baselineCount =
                $runner->baselineExistingInstallation();

            $progress->update(
                100,
                $baselineCount > 0
                    ? 'Installation existante enregistrée comme référence.'
                    : 'Aucune nouvelle migration à exécuter.'
            );

            $_SESSION['install_execution_complete'] = true;
            $_SESSION['install_execution_summary'] =
                $runner->summary();

            respond([
                'success' => true,
                'complete' => true,
                'mode' => 'baseline',
                'message' =>
                    'Installation existante détectée : '
                    . $baselineCount
                    . ' migration(s) enregistrée(s) sans réexécution.',
                'progress' => $progress->current(),
                'summary' => $runner->summary(),
            ]);
        }

        $pending = $runner->pending();

        $_SESSION['install_pending_migrations'] =
            $pending;

        $_SESSION['install_total_migrations'] =
            count($pending);

        $_SESSION['install_completed_migrations'] = 0;
        unset(
            $_SESSION['install_execution_complete'],
            $_SESSION['install_execution_summary']
        );

        if ($pending === []) {
            $progress->update(
                100,
                'Aucune migration en attente.'
            );

            $_SESSION['install_execution_complete'] = true;
            $_SESSION['install_execution_summary'] =
                $runner->summary();

            respond([
                'success' => true,
                'complete' => true,
                'mode' => 'nothing',
                'message' => 'Aucune migration en attente.',
                'progress' => $progress->current(),
                'summary' => $runner->summary(),
            ]);
        }

        $progress->update(
            0,
            count($pending)
            . ' migration(s) prête(s) à être exécutée(s).'
        );

        respond([
            'success' => true,
            'complete' => false,
            'mode' => 'install',
            'total' => count($pending),
            'progress' => $progress->current(),
        ]);
    }

    if ($action === 'next') {
        $pending = $_SESSION['install_pending_migrations']
            ?? [];

        if (!is_array($pending)) {
            $pending = [];
        }

        $total = max(
            1,
            (int)(
                $_SESSION['install_total_migrations']
                ?? count($pending)
            )
        );

        $completed = (int)(
            $_SESSION['install_completed_migrations']
            ?? 0
        );

        if ($pending === []) {
            $progress->update(
                100,
                'Installation de la base terminée.'
            );

            $_SESSION['install_execution_complete'] = true;
            $_SESSION['install_execution_summary'] =
                $runner->summary();

            respond([
                'success' => true,
                'complete' => true,
                'progress' => $progress->current(),
                'summary' => $runner->summary(),
            ]);
        }

        $migration = array_shift($pending);
        $_SESSION['install_pending_migrations'] =
            $pending;

        $result = $runner->execute(
            is_array($migration)
                ? $migration
                : []
        );

        $completed++;
        $_SESSION['install_completed_migrations'] =
            $completed;

        $percent = (int)round(
            ($completed / $total) * 100
        );

        $progress->update(
            $percent,
            'Migration '
            . $result['name']
            . ' terminée.'
        );

        $complete = $pending === [];

        if ($complete) {
            $_SESSION['install_execution_complete'] = true;
            $_SESSION['install_execution_summary'] =
                $runner->summary();
        }

        respond([
            'success' => true,
            'complete' => $complete,
            'migration' => $result,
            'progress' => $progress->current(),
            'summary' => $complete
                ? $runner->summary()
                : null,
        ]);
    }

    respond([
        'success' => false,
        'message' => 'Action inconnue.',
    ], 400);
} catch (\Throwable $exception) {
    $progress = new InstallationProgress();
    $progress->update(
        (int)($progress->current()['percent'] ?? 0),
        'Installation interrompue : '
        . $exception->getMessage()
    );

    respond([
        'success' => false,
        'message' => $exception->getMessage(),
        'progress' => $progress->current(),
    ], 500);
}
