<?php
namespace App\Core;

/**
 * Authentication for internal users (agents, leads, admins). Stands in for
 * "inherit the ERP user authentication and role framework" (FR-SUP-110)
 * until this module is wired into a real ERP's auth service.
 */
class Auth
{
    private static ?array $user = null;

    public static function boot(): void
    {
        Session::start(Config::get('session.agent_cookie', 'std_agent_sess'));
    }

    public static function attempt(string $email, string $password): bool
    {
        $user = Database::one(
            'SELECT u.*, r.code AS role_code, r.name AS role_name FROM users u
             JOIN roles r ON r.id = u.role_id
             WHERE u.email = :email AND u.is_active = 1',
            ['email' => $email]
        );
        if (!$user || !password_verify($password, $user['password_hash'])) {
            return false;
        }
        Session::regenerate();
        $_SESSION['user_id'] = (int)$user['id'];
        Database::run('UPDATE users SET last_login_at = NOW() WHERE id = :id', ['id' => $user['id']]);
        self::$user = $user;
        return true;
    }

    public static function logout(): void
    {
        Session::destroy();
        self::$user = null;
    }

    public static function check(): bool
    {
        return !empty($_SESSION['user_id']);
    }

    public static function user(): ?array
    {
        if (self::$user !== null) return self::$user;
        if (empty($_SESSION['user_id'])) return null;
        self::$user = Database::one(
            'SELECT u.*, r.code AS role_code, r.name AS role_name FROM users u
             JOIN roles r ON r.id = u.role_id WHERE u.id = :id',
            ['id' => $_SESSION['user_id']]
        );
        return self::$user;
    }

    public static function id(): ?int
    {
        return isset($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : null;
    }

    public static function role(): ?string
    {
        return self::user()['role_code'] ?? null;
    }

    public static function isAny(array $roles): bool
    {
        return in_array(self::role(), $roles, true);
    }

    private static ?array $permissionCache = null;

    /**
     * Fine-grained permission check backed by the admin-editable role_permissions
     * matrix (see Permissions::all()). ADMIN always passes, by design — the matrix
     * governs L1/L2/L3/LEAD/HEAD/FINANCE and can never be configured to lock every
     * account out of the system.
     */
    public static function can(string $key): bool
    {
        if (self::role() === 'ADMIN') return true;
        if (self::$permissionCache === null) {
            $roleId = self::user()['role_id'] ?? null;
            self::$permissionCache = $roleId
                ? array_column(Database::all('SELECT permission_key FROM role_permissions WHERE role_id = :r', ['r' => $roleId]), 'permission_key')
                : [];
        }
        return in_array($key, self::$permissionCache, true);
    }

    public static function requireLogin(): callable
    {
        return function () {
            self::boot();
            if (!self::check()) {
                $base = Request::basePath();
                header('Location: ' . $base . '/login?next=' . urlencode(Request::path()));
                return false;
            }
            return true;
        };
    }

    public static function requireRole(array $roles): callable
    {
        return function () use ($roles) {
            self::boot();
            if (!self::check()) {
                header('Location: ' . Request::basePath() . '/login');
                return false;
            }
            if (!self::isAny($roles)) {
                http_response_code(403);
                echo '<!doctype html><html><body style="font-family:sans-serif;padding:40px"><h1>403</h1><p>You do not have permission to view this page.</p></body></html>';
                return false;
            }
            return true;
        };
    }
}
