<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\Database;
use App\Core\Env;
use App\Core\Request;
use App\Core\Response;
use Throwable;

final class DebugController
{
    public function migrationCheck(Request $request): void
    {
        $started = microtime(true);

        $checks = [
            'php' => $this->checkPhp(),
            'env' => $this->checkEnv(),
            'database' => $this->checkDatabase(),
            'schema' => $this->checkSchema(),
            'tables' => $this->checkTables(),
            'storage' => $this->checkStorage(),
            'routes' => $this->checkRoutes(),
        ];

        $ok = true;
        foreach ($checks as $check) {
            if (is_array($check) && (($check['ok'] ?? false) === false)) {
                $ok = false;
                break;
            }
        }

        Response::json([
            'ok' => $ok,
            'message' => $ok
                ? 'Migração PHP operacional nos principais pontos.'
                : 'Migração PHP possui pendências. Verifique checks com ok=false.',
            'runtime_ms' => round((microtime(true) - $started) * 1000, 2),
            'checks' => $checks,
        ]);
    }

    private function checkPhp(): array
    {
        return [
            'ok' => true,
            'version' => PHP_VERSION,
            'extensions' => [
                'pdo' => extension_loaded('pdo'),
                'pdo_pgsql' => extension_loaded('pdo_pgsql'),
                'json' => extension_loaded('json'),
                'fileinfo' => extension_loaded('fileinfo'),
            ],
        ];
    }

    private function checkEnv(): array
    {
        $keys = ['DB_HOST', 'DB_PORT', 'DB_NAME', 'DB_USER', 'CORS_ORIGINS', 'PUBLIC_BASE_URL', 'APP_URL'];
        $values = [];
        foreach ($keys as $key) {
            $value = Env::get($key);
            $values[$key] = [
                'defined' => $value !== null && $value !== '',
                'value' => in_array($key, ['DB_USER', 'DB_NAME', 'DB_HOST', 'DB_PORT'], true) ? $value : ($value ? 'configured' : null),
            ];
        }

        return [
            'ok' => ($values['DB_HOST']['defined'] ?? false)
                && ($values['DB_NAME']['defined'] ?? false)
                && ($values['DB_USER']['defined'] ?? false),
            'items' => $values,
        ];
    }

    private function checkDatabase(): array
    {
        try {
            $pdo = Database::pdo();
            $row = $pdo->query('SELECT current_database() AS database, current_schema() AS schema, version() AS version')
                ->fetch(\PDO::FETCH_ASSOC);

            return [
                'ok' => true,
                'database' => $row['database'] ?? null,
                'schema' => $row['schema'] ?? null,
                'version' => $row['version'] ?? null,
            ];
        } catch (Throwable $e) {
            return [
                'ok' => false,
                'error' => $e->getMessage(),
            ];
        }
    }

    private function checkSchema(): array
    {
        return $this->existsSql(
            "SELECT 1 FROM information_schema.schemata WHERE schema_name = 'gestao_sisprom'",
            'Schema gestao_sisprom encontrado.',
            'Schema gestao_sisprom não encontrado.'
        );
    }

    private function checkTables(): array
    {
        $required = [
            'users',
            'municipios',
            'usuario_municipios',
            'profiles',
            'user_roles',
            'branding_municipio',
            'modulos',
            'municipio_modulos',
            'secretarias',
            'departamentos',
            'setores',
            'auditoria',
            'sessoes_login',
        ];

        $items = [];
        foreach ($required as $table) {
            $items[$table] = $this->tableExists('gestao_sisprom', $table);
        }

        $ok = !in_array(false, array_column($items, 'ok'), true);

        return [
            'ok' => $ok,
            'items' => $items,
        ];
    }

    private function checkStorage(): array
    {
        $root = dirname(__DIR__, 2);
        $paths = [
            'uploads' => $root . DIRECTORY_SEPARATOR . 'uploads',
            'uploads_identidade_visual' => $root . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'identidade_visual',
            'public_uploads' => $root . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'uploads',
            'public_identidade_visual' => $root . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'identidade_visual',
            'storage_logs' => $root . DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR . 'logs',
        ];

        $items = [];
        foreach ($paths as $key => $path) {
            if (!is_dir($path)) {
                @mkdir($path, 0775, true);
            }
            $items[$key] = [
                'path' => $path,
                'exists' => is_dir($path),
                'writable' => is_dir($path) && is_writable($path),
            ];
        }

        $ok = true;
        foreach ($items as $item) {
            if (!$item['exists']) {
                $ok = false;
                break;
            }
        }

        return [
            'ok' => $ok,
            'items' => $items,
        ];
    }

    private function checkRoutes(): array
    {
        return [
            'ok' => true,
            'items' => [
                'auth_login' => '/api/v1/auth/login',
                'auth_me' => '/api/v1/auth/me',
                'compat' => '/api/v1/compat/{table}',
                'functions' => '/api/v1/functions/{name}',
                'storage_upload' => '/api/v1/storage/{bucket}/upload',
                'storage_public' => '/uploads/identidade_visual/... ou /api/v1/storage/public/...',
                'bi_iptu_resumo' => '/api/v1/bi/iptu/resumo',
                'bi_iptu_status' => '/api/v1/bi/iptu/status',
                'mapa_config' => '/api/v1/mapa/config',
                'migration_check' => '/api/v1/debug/migration-check',
            ],
        ];
    }

    private function tableExists(string $schema, string $table): array
    {
        return $this->existsSql(
            'SELECT 1 FROM information_schema.tables WHERE table_schema = :schema AND table_name = :table',
            "Tabela {$schema}.{$table} encontrada.",
            "Tabela {$schema}.{$table} não encontrada.",
            ['schema' => $schema, 'table' => $table]
        );
    }

    private function existsSql(string $sql, string $success, string $failure, array $params = []): array
    {
        try {
            $stmt = Database::pdo()->prepare($sql);
            $stmt->execute($params);
            $exists = (bool) $stmt->fetchColumn();

            return [
                'ok' => $exists,
                'message' => $exists ? $success : $failure,
            ];
        } catch (Throwable $e) {
            return [
                'ok' => false,
                'message' => $failure,
                'error' => $e->getMessage(),
            ];
        }
    }
}
