<?php

namespace WPD\Web;

use WPD\Application\Config;
use WPD\Diagnostics\ScanOrchestrator;
use WPD\Domain\ScanContext;
use WPD\Report\ReportBuilder;
use WPD\Security\AccessGuard;
use WPD\Security\Csrf;
use WPD\Security\CredentialVault;
use WPD\Security\TransportPolicy;
use WPD\WordPress\ConfigParser;
use WPD\WordPress\InstallationLocator;
use WPD\WordPress\PathGuard;

final class Controller
{
    private $config;
    private $transport;
    private $guard;
    private $view;

    public function __construct(Config $config, TransportPolicy $transport, AccessGuard $guard)
    {
        $this->config = $config;
        $this->transport = $transport;
        $this->guard = $guard;
        $this->view = new View();
    }

    public function handle()
    {
        if (!$this->guard->accessAvailable()) {
            $this->guard->isAuthenticated();
            http_response_code(403);
            $this->view->unavailable();
            return;
        }

        $action = isset($_GET['action']) ? (string) $_GET['action'] : '';
        $error = false;

        if ($action === 'login' && $_SERVER['REQUEST_METHOD'] === 'POST') {
            if (!Csrf::validate(isset($_POST['csrf']) ? $_POST['csrf'] : null)
                || !$this->guard->attempt(isset($_POST['access_token']) ? (string) $_POST['access_token'] : '')) {
                $error = true;
            } else {
                $this->redirect('./');
            }
        }

        if (!$this->guard->isAuthenticated()) {
            $this->view->login(Csrf::token(), $error, $this->transport->mode() === TransportPolicy::HTTP_EMERGENCY);
            return;
        }

        if ($action === 'logout' && $_SERVER['REQUEST_METHOD'] === 'POST') {
            $this->requireCsrf();
            $this->guard->logout();
            $this->redirect('./');
        }

        $pathGuard = new PathGuard($this->config->get('allowed_root'));
        $locator = new InstallationLocator($pathGuard);
        $parser = new ConfigParser($pathGuard);
        $orchestrator = new ScanOrchestrator();
        $root = $locator->detect();

        if ($action === 'start' && $_SERVER['REQUEST_METHOD'] === 'POST') {
            $this->requireCsrf();
            if ($root === null) {
                $this->view->setup(Csrf::token(), false, null, 'No se encontró WordPress en la ruta configurada. Corrige allowed_root mediante FTP.');
                return;
            }
            $manual = $this->manualDatabase();
            if ($manual) {
                $sealed = (new CredentialVault($this->config))->seal($manual, isset($_SESSION['wpd_activation_id']) ? $_SESSION['wpd_activation_id'] : '');
                $manual = array_fill_keys(array_keys($manual), '');
                if ($sealed === null) {
                    unset($_SESSION['wpd_manual_database']);
                    $this->view->setup(Csrf::token(), true, $parser->parse($root), 'No se pudo proteger la conexión manual. Utiliza la detección automática o revisa la extensión OpenSSL.');
                    return;
                }
                $_SESSION['wpd_manual_database'] = $sealed;
            } else {
                unset($_SESSION['wpd_manual_database']);
            }
            $_SESSION['wpd_scan'] = $orchestrator->start($root);
            $this->redirect('./');
        }

        if ($action === 'step' && $_SERVER['REQUEST_METHOD'] === 'POST') {
            $this->requireCsrf(true);
            if (empty($_SESSION['wpd_scan']) || !is_array($_SESSION['wpd_scan']) || $root === null) {
                $this->json(array('ok' => false, 'message' => 'No hay un análisis disponible.'), 409);
            }
            $state = $_SESSION['wpd_scan'];
            $manual = array();
            if (isset($_SESSION['wpd_manual_database']) && is_array($_SESSION['wpd_manual_database'])) {
                $opened = (new CredentialVault($this->config))->open($_SESSION['wpd_manual_database'], isset($_SESSION['wpd_activation_id']) ? $_SESSION['wpd_activation_id'] : '');
                if (is_array($opened)) {
                    $manual = $opened;
                } else {
                    unset($_SESSION['wpd_manual_database']);
                }
            }
            $context = new ScanContext($root, $pathGuard, $parser, $manual);
            $state = $orchestrator->step($state, $context);
            $manual = array_fill_keys(array_keys($manual), '');
            $_SESSION['wpd_scan'] = $state;
            if (isset($state['checks']['database'])) {
                unset($_SESSION['wpd_manual_database']);
            }
            if (!empty($_POST['fallback'])) {
                $this->redirect('./');
            }
            $this->json(array('ok' => true, 'progress' => $orchestrator->progress($state)));
        }

        if ($action === 'clear' && $_SERVER['REQUEST_METHOD'] === 'POST') {
            $this->requireCsrf();
            unset($_SESSION['wpd_scan'], $_SESSION['wpd_manual_database']);
            $this->redirect('./');
        }

        if (in_array($action, array('export_json', 'export_html'), true) && $_SERVER['REQUEST_METHOD'] === 'POST') {
            if ($this->transport->mode() !== TransportPolicy::HTTPS) {
                http_response_code(403);
                $this->view->message('Exportación no disponible', 'El modo HTTP de emergencia no permite descargar informes.');
                return;
            }
            $this->requireCsrf();
            if (empty($_SESSION['wpd_scan']['complete']) || $root === null) {
                http_response_code(409);
                $this->view->message('No se puede exportar', 'No hay un informe completo disponible.');
                return;
            }
            $state = $_SESSION['wpd_scan'];
            $context = new ScanContext($root, $pathGuard, $parser);
            $builder = new ReportBuilder();
            $report = $builder->build($state, $context);
            if ($action === 'export_json') {
                header('Content-Type: application/json; charset=utf-8');
                header('Content-Disposition: attachment; filename="diagnostico-wordpress-' . $state['scan_id'] . '.json"');
                echo $builder->json($report);
            } else {
                header('Content-Type: text/html; charset=utf-8');
                header('Content-Disposition: attachment; filename="diagnostico-wordpress-' . $state['scan_id'] . '.html"');
                echo $builder->standaloneHtml($report);
            }
            return;
        }

        if (!empty($_SESSION['wpd_scan']) && is_array($_SESSION['wpd_scan'])) {
            $state = $_SESSION['wpd_scan'];
            if ($root === null) {
                unset($_SESSION['wpd_scan'], $_SESSION['wpd_manual_database']);
                $this->redirect('./');
            }
            if (!empty($state['complete'])) {
                unset($_SESSION['wpd_manual_database']);
                $context = new ScanContext($root, $pathGuard, $parser);
                $report = (new ReportBuilder())->build($state, $context);
                $this->view->report(Csrf::token(), $report, $this->transport->mode() === TransportPolicy::HTTPS);
            } else {
                $this->view->progress(Csrf::token(), $orchestrator->progress($state), $this->transport->mode() === TransportPolicy::HTTP_EMERGENCY);
            }
            return;
        }

        $configStatus = $root ? $parser->parse($root) : null;
        $this->view->setup(Csrf::token(), $root !== null, $configStatus, null, $this->transport->mode() === TransportPolicy::HTTP_EMERGENCY);
    }

    private function manualDatabase()
    {
        if ($this->transport->mode() !== TransportPolicy::HTTPS || empty($_POST['use_manual_database'])) {
            return array();
        }
        $fields = array(
            'name' => isset($_POST['db_name']) ? trim((string) $_POST['db_name']) : '',
            'user' => isset($_POST['db_user']) ? trim((string) $_POST['db_user']) : '',
            'password' => isset($_POST['db_password']) ? (string) $_POST['db_password'] : '',
            'host' => isset($_POST['db_host']) ? trim((string) $_POST['db_host']) : '',
            'prefix' => isset($_POST['db_prefix']) ? trim((string) $_POST['db_prefix']) : '',
        );
        foreach ($fields as $key => $value) {
            if (strlen($value) > 512) {
                $fields[$key] = substr($value, 0, 512);
            }
        }
        return $fields;
    }

    private function requireCsrf($json = false)
    {
        $token = isset($_POST['csrf']) ? $_POST['csrf'] : null;
        if (!Csrf::validate($token)) {
            if ($json) {
                $this->json(array('ok' => false, 'message' => 'La sesión ha caducado.'), 419);
            }
            http_response_code(419);
            $this->view->message('La sesión ha caducado', 'Recarga la página antes de continuar.');
            exit;
        }
    }

    private function redirect($location)
    {
        header('Location: ' . $location, true, 303);
        exit;
    }

    private function json(array $data, $status = 200)
    {
        http_response_code($status);
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        exit;
    }
}
