<?php

declare(strict_types=1);

namespace App\Support;

use PDO;
use PDOException;

final class Diagnostics
{
    public static function run(bool $includeHttp = false): array
    {
        $checks = [];
        $projectRoot = dirname(__DIR__, 2);
        $storageDir = $projectRoot . '/storage';
        $uploadsDir = $storageDir . '/uploads';
        $envFile = $projectRoot . '/.env';
        $autoloadFile = $projectRoot . '/vendor/autoload.php';
        $baseUrl = trim((string) env('APP_URL', ''));

        $checks[] = self::check('PHP 8.1+', version_compare(PHP_VERSION, '8.1.0', '>='), 'Atual: ' . PHP_VERSION, 'ambiente');
        $checks[] = self::check('Extensão PDO', extension_loaded('pdo'), extension_loaded('pdo') ? 'OK' : 'Extensão ausente.', 'ambiente');
        $checks[] = self::check('Extensão pdo_mysql', extension_loaded('pdo_mysql'), extension_loaded('pdo_mysql') ? 'OK' : 'Extensão ausente.', 'ambiente');
        $checks[] = self::check('Extensão session', extension_loaded('session'), extension_loaded('session') ? 'OK' : 'Extensão ausente.', 'ambiente');
        $checks[] = self::check('Extensão fileinfo', extension_loaded('fileinfo'), extension_loaded('fileinfo') ? 'OK' : 'Extensão ausente.', 'ambiente');
        $checks[] = self::check('Arquivo .env', file_exists($envFile), file_exists($envFile) ? 'Arquivo encontrado.' : 'Crie o arquivo .env a partir do .env.example.', 'configuração');
        $checks[] = self::check('Composer autoload', file_exists($autoloadFile), file_exists($autoloadFile) ? 'vendor/autoload.php encontrado.' : 'Rode composer install.', 'configuração');
        $checks[] = self::check('APP_URL configurada', $baseUrl !== '' && filter_var($baseUrl, FILTER_VALIDATE_URL), $baseUrl !== '' ? $baseUrl : 'Defina APP_URL no .env.', 'configuração');
        $checks[] = self::check('Pasta storage', is_dir($storageDir) && is_writable($storageDir), is_dir($storageDir) ? $storageDir : 'Diretório não encontrado.', 'arquivos');
        $checks[] = self::check('Pasta storage/uploads', is_dir($uploadsDir) && is_writable($uploadsDir), is_dir($uploadsDir) ? $uploadsDir : 'Diretório não encontrado.', 'arquivos');
        $checks[] = self::check('Arquivo .htaccess público', file_exists($projectRoot . '/public/.htaccess'), file_exists($projectRoot . '/public/.htaccess') ? 'OK' : 'Arquivo ausente em public/.htaccess.', 'configuração');
        $checks[] = self::check('Classe Dompdf', class_exists(\Dompdf\Dompdf::class), class_exists(\Dompdf\Dompdf::class) ? 'Disponível.' : 'Biblioteca ausente.', 'dependências');

        try {
            $pdo = self::connectFromEnv();
            $checks[] = self::check('Conexão com banco', true, 'Conexão estabelecida com sucesso.', 'banco');
            $checks = array_merge($checks, self::databaseChecks($pdo));
        } catch (PDOException $e) {
            $checks[] = self::check('Conexão com banco', false, $e->getMessage(), 'banco');
        }

        if ($includeHttp && $baseUrl !== '' && function_exists('curl_init')) {
            $checks = array_merge($checks, self::httpChecks($baseUrl));
        }

        return $checks;
    }

    public static function summarize(array $checks): array
    {
        $summary = ['ok' => 0, 'warning' => 0, 'error' => 0];

        foreach ($checks as $check) {
            $summary[$check['status']]++;
        }

        return $summary;
    }

    private static function connectFromEnv(): PDO
    {
        $dsn = sprintf(
            'mysql:host=%s;port=%s;dbname=%s;charset=%s',
            env('DB_HOST', '127.0.0.1'),
            env('DB_PORT', '3306'),
            env('DB_NAME', 'ficha_admissao'),
            'utf8mb4'
        );

        return new PDO($dsn, (string) env('DB_USER', 'root'), (string) env('DB_PASS', ''), [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    }

    private static function databaseChecks(PDO $pdo): array
    {
        $checks = [];
        $requiredTables = ['admin_users', 'admissions', 'dependents', 'academic_infos', 'attachments'];

        foreach ($requiredTables as $table) {
            try {
                $st = $pdo->query('SELECT COUNT(*) FROM ' . $table);
                $count = (int) $st->fetchColumn();
                $checks[] = self::check('Tabela ' . $table, true, 'Registros atuais: ' . $count, 'banco');
            } catch (PDOException $e) {
                $checks[] = self::check('Tabela ' . $table, false, 'Tabela ausente ou inacessível.', 'banco');
            }
        }

        try {
            $hasRoleColumn = (bool) $pdo->query("SHOW COLUMNS FROM admin_users LIKE 'role'")->fetch();
            $checks[] = self::check('Coluna role em admin_users', $hasRoleColumn, $hasRoleColumn ? 'Tipos de usuário habilitados.' : 'Rode php scripts/patch_admin_roles.php --force', 'banco');

            $adminCountSql = $hasRoleColumn
                ? "SELECT COUNT(*) FROM admin_users WHERE is_active = 1 AND role = 'admin'"
                : 'SELECT COUNT(*) FROM admin_users WHERE is_active = 1';

            $activeAdmins = (int) $pdo->query($adminCountSql)->fetchColumn();
            $checks[] = self::check('Admin ativo disponível', $activeAdmins > 0, 'Admins ativos: ' . $activeAdmins, 'segurança');
        } catch (PDOException $e) {
            $checks[] = self::check('Admin ativo disponível', false, 'Não foi possível validar os admins.', 'segurança');
        }

        return $checks;
    }

    private static function httpChecks(string $baseUrl): array
    {
        $checks = [];
        $targets = [
            ['path' => '/', 'label' => 'Página pública'],
            ['path' => '/admin/login', 'label' => 'Login admin'],
        ];

        foreach ($targets as $target) {
            $url = rtrim($baseUrl, '/') . $target['path'];
            $result = self::request($url);
            $checks[] = self::check(
                $target['label'],
                $result['ok'],
                $result['message'],
                'http'
            );
        }

        return $checks;
    }

    private static function request(string $url): array
    {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_CONNECTTIMEOUT => 5,
            CURLOPT_TIMEOUT => 10,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_USERAGENT => 'AdmissoesDiagnostics/1.0',
        ]);

        $body = curl_exec($ch);
        $status = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
        $error = curl_error($ch);
        curl_close($ch);

        if ($body === false) {
            return ['ok' => false, 'message' => 'Falha HTTP: ' . $error];
        }

        if ($status < 200 || $status >= 400) {
            return ['ok' => false, 'message' => 'HTTP ' . $status . ' em ' . $url];
        }

        return ['ok' => true, 'message' => 'HTTP ' . $status . ' em ' . $url];
    }

    private static function check(string $label, bool $success, string $details, string $group): array
    {
        return [
            'label' => $label,
            'status' => $success ? 'ok' : 'error',
            'details' => $details,
            'group' => $group,
        ];
    }
}
