<?php
/**
 * core/App.php
 * Bootstrap y punto de entrada del ERP.
 *
 * Uso desde index.php (punto de entrada del módulo ERP):
 *
 *   define('APP_ROOT', __DIR__);
 *   require_once __DIR__ . '/core/App.php';
 *   App::run();
 *
 * Los archivos lab_*.php legacy en raíz siguen funcionando directamente
 * sin pasar por App — compatibilidad total garantizada.
 */

// ─── Constante de raíz del proyecto ─────────────────────────────────────────
if (!defined('APP_ROOT')) {
    define('APP_ROOT', dirname(__DIR__));
}

// ─── Dependencias del core ───────────────────────────────────────────────────
require_once APP_ROOT . '/config/config.php';
require_once APP_ROOT . '/core/Helpers.php';
require_once APP_ROOT . '/core/Auth.php';
require_once APP_ROOT . '/core/Rbac.php';
require_once APP_ROOT . '/core/Router.php';
require_once APP_ROOT . '/core/Layout.php';

class App
{
    // ─── Punto de entrada ────────────────────────────────────────────────────

    public static function run(): void
    {
        self::boot();

        $router = new Router();

        // Rutas públicas: sin verificación de sesión
        if (!$router->isPublic()) {
            Auth::requireLogin();
            // Enfermeros van a su portal propio, no al panel ERP
            if (Auth::isEnfermero()) {
                header('Location: ' . APP_ROOT . '/../enfermero_portal.php');
                exit;
            }
            // Recepcionistas con IP registrada: solo pueden acceder a su desk
            if (Auth::role() === 'recepcionista') {
                $mod  = $router->getModule();
                $view = $router->getView();
                if ($mod === 'turnero' && $view === 'recepcion') {
                    $deskId = (int)($_GET['desk_id'] ?? 0);
                    $assignedDesk = self::recepIpDesk();
                    if ($assignedDesk && $deskId !== $assignedDesk) {
                        header('Location: /erp.php?m=turnero&v=recepcion&desk_id=' . $assignedDesk);
                        exit;
                    }
                }
            }
            // Bacteriólogos: sin dashboard ni historial; redirige según IP
            if (Auth::isBacteriologo()) {
                $mod  = $router->getModule();
                $view = $router->getView();
                $blocked = ($mod === 'dashboard')
                    || ($mod === 'turnero' && in_array($view, ['dashboard', 'historial'], true));
                if ($blocked) {
                    header('Location: ' . self::bacteDefaultUrl());
                    exit;
                }
            }
        }

        self::dispatch($router);
    }

    // ─── Bootstrap ──────────────────────────────────────────────────────────

    /**
     * Inicializa la sesión y la zona horaria.
     * Se puede llamar también desde archivos legacy para obtener sesión lista.
     */
    public static function boot(): void
    {
        if (session_status() === PHP_SESSION_NONE) {
            // Cookies de sesión seguras
            session_set_cookie_params([
                'lifetime' => 0,
                'path'     => '/',
                'secure'   => !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off',
                'httponly' => true,
                'samesite' => 'Lax',
            ]);
            session_start();
        }

        date_default_timezone_set(defined('TIMEZONE') ? TIMEZONE : 'America/Bogota');
    }

    // ─── Dispatch ───────────────────────────────────────────────────────────

    private static function dispatch(Router $router): void
    {
        try {
            $viewFile = $router->resolveFile();
        } catch (RuntimeException $e) {
            self::render404($router->getModule(), $router->getView());
            return;
        }

        // Verificar permiso de módulo (solo en rutas protegidas)
        if (!$router->isPublic()) {
            $module = $router->getModule();
            // Si el módulo está registrado en SYSTEM_MODULES, verificar acceso
            if (defined('SYSTEM_MODULES') && array_key_exists($module, SYSTEM_MODULES)) {
                if (!Rbac::hasModule($module)) {
                    self::render403($module);
                    return;
                }
            }
        }

        // Ejecutar la vista del módulo
        include $viewFile;
    }

    // ─── Helpers de rol ─────────────────────────────────────────────────────

    /** IP real del cliente, soporta proxy con X-Forwarded-For. */
    public static function clientIp(): string
    {
        $raw = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR'] ?? '';
        return trim(explode(',', $raw)[0]);
    }

    /**
     * Devuelve el lugar_id de recepción asignado a la IP del cliente, o null si no está registrada.
     */
    private static function recepIpDesk(): ?int
    {
        try {
            $pdo = Database::getInstance()->getConnection();
            $st  = $pdo->prepare(
                "SELECT d.lugar_id FROM turnero_dispositivos d
                 JOIN turnero_lugares l ON l.id = d.lugar_id
                 WHERE d.ip = ? AND d.activo = 1 AND l.tipo = 'recepcion' LIMIT 1"
            );
            $st->execute([self::clientIp()]);
            $id = $st->fetchColumn();
            return $id ? (int)$id : null;
        } catch (\Throwable $_) {
            return null;
        }
    }

    /**
     * URL de destino para bacteriólogo según IP del cliente.
     * IP registrada en turnero_dispositivos → ese lugar.
     * IP no registrada → primer lugar de tipo muestras.
     */
    private static function bacteDefaultUrl(): string
    {
        $base = '/erp.php?m=turnero&v=lugar&lugar_id=';
        try {
            $pdo = Database::getInstance()->getConnection();
            // 1. Por token de navegador
            $tok = trim($_COOKIE['turnero_token'] ?? '');
            if ($tok) {
                $s = $pdo->prepare(
                    "SELECT lugar_id FROM turnero_dispositivos WHERE token = ? AND activo = 1 LIMIT 1"
                );
                $s->execute([$tok]);
                $row = $s->fetch(PDO::FETCH_ASSOC);
                if ($row) return $base . (int)$row['lugar_id'];
            }
            // 2. Por IP
            $ip  = self::clientIp();
            $s = $pdo->prepare(
                "SELECT lugar_id FROM turnero_dispositivos WHERE ip = ? AND token IS NULL AND activo = 1 LIMIT 1"
            );
            $s->execute([$ip]);
            $row = $s->fetch(PDO::FETCH_ASSOC);
            if ($row) return $base . (int)$row['lugar_id'];
            // 3. Primer lugar de toma de muestras
            $first = $pdo->query(
                "SELECT id FROM turnero_lugares WHERE activo=1 AND tipo='muestras' ORDER BY sort_order LIMIT 1"
            )->fetch(PDO::FETCH_ASSOC);
            if ($first) return $base . (int)$first['id'];
        } catch (\Throwable $_) {}
        return '/erp.php?m=turnero';
    }

    // ─── Páginas de error ────────────────────────────────────────────────────

    private static function render404(string $module, string $view): void
    {
        http_response_code(404);
        Layout::open('Página no encontrada', 'fas fa-exclamation-triangle');
        echo '<div class="container-fluid py-5 text-center">';
        echo '<i class="fas fa-exclamation-triangle fa-4x text-warning mb-3"></i>';
        echo '<h2>404 — Módulo no encontrado</h2>';
        echo '<p class="text-muted">El módulo <code>' . esc($module) . '</code> / vista <code>' . esc($view) . '</code> no existe.</p>';
        echo '<a href="' . esc(APP_URL ?? '/') . '" class="btn btn-primary"><i class="fas fa-home me-1"></i>Ir al inicio</a>';
        echo '</div>';
        Layout::close();
    }

    private static function render403(string $module): void
    {
        http_response_code(403);
        Layout::open('Acceso denegado', 'fas fa-lock');
        echo '<div class="container-fluid py-5 text-center">';
        echo '<i class="fas fa-lock fa-4x text-danger mb-3"></i>';
        echo '<h2>403 — Sin permiso</h2>';
        echo '<p class="text-muted">Tu rol no tiene acceso al módulo <code>' . esc($module) . '</code>.</p>';
        echo '<a href="' . esc(APP_URL ?? '/') . '" class="btn btn-secondary"><i class="fas fa-arrow-left me-1"></i>Volver</a>';
        echo '</div>';
        Layout::close();
    }
}
