<?php
namespace Core;

class Auth {
    public static function login(array $user): void {
        $_SESSION['user'] = $user;
        $_SESSION['user_id'] = $user['id'];
        $_SESSION['last_activity'] = time();
        self::refreshPermissions();
    }
    
    public static function logout(): void {
        unset($_SESSION['user'], $_SESSION['user_id'], $_SESSION['permissions'], $_SESSION['otp_pending'], $_SESSION['otp_user_id']);
        session_destroy();
    }

    /**
     * Log the user out because their trial expired, but (unlike logout())
     * keep the session alive and stash who/what org they were, so the billing
     * flow can bill the right organization and log the same user back in
     * once they pay — without ever granting authenticated access meanwhile.
     */
    public static function logoutForBilling(int $orgId, ?int $userId = null): void {
        unset($_SESSION['user'], $_SESSION['user_id'], $_SESSION['permissions'], $_SESSION['otp_pending'], $_SESSION['otp_user_id']);
        $_SESSION['billing_org_id'] = $orgId;
        if ($userId) {
            $_SESSION['billing_user_id'] = $userId;
        }
    }

    public static function clearBillingContext(): void {
        unset($_SESSION['billing_org_id'], $_SESSION['billing_user_id']);
    }

    /**
     * Seconds since the last request this user made while authenticated, or
     * null if there's no baseline yet (e.g. very first request after login,
     * handled by touchActivity() below).
     */
    public static function idleSeconds(): ?int {
        $lastActivity = $_SESSION['last_activity'] ?? null;
        return $lastActivity === null ? null : (time() - (int)$lastActivity);
    }

    /** Record this request as activity, resetting the idle clock. */
    public static function touchActivity(): void {
        $_SESSION['last_activity'] = time();
    }
    
    public static function user(): ?array {
        return $_SESSION['user'] ?? null;
    }
    
    public static function check(): bool {
        return isset($_SESSION['user_id']) && !self::isPendingOtp();
    }
    
    public static function id(): ?int {
        return $_SESSION['user_id'] ?? null;
    }
    
    public static function orgId(): ?int {
        return $_SESSION['user']['org_id'] ?? null;
    }
    
    public static function hasRole(string $roleName): bool {
        return ($_SESSION['user']['entity_type'] ?? '') === $roleName;
    }
    
    public static function hasPermission(string $module, string $action): bool {
        if (self::isSuperAdmin()) return true;
        $perms = self::getPermissions();
        return isset($perms[$module]) && in_array($action, $perms[$module]);
    }
    
    public static function isSuperAdmin(): bool {
        return !empty($_SESSION['user']['is_super_admin']) || self::hasRole('super_admin') || self::hasRole('superadmin');
    }
    
    public static function isContractorUser(): bool {
        return self::hasRole('contractor_user');
    }

    public static function isSupplierUser(): bool {
        return self::hasRole('supplier_user');
    }

    public static function isOrgUser(): bool {
        return self::hasRole('org_user');
    }
    
    public static function getPermissions(): array {
        if (!isset($_SESSION['permissions'])) {
            self::refreshPermissions();
        }
        return $_SESSION['permissions'] ?? [];
    }
    
    public static function refreshPermissions(): void {
        if (!isset($_SESSION['user_id'])) return;

        $db = \Database::getInstance();

        $stmt = $db->prepare(
            "SELECT DISTINCT p.module, p.action
             FROM permissions p
             INNER JOIN role_permissions rp ON p.id = rp.permission_id
             INNER JOIN user_roles ur ON rp.role_id = ur.role_id
             WHERE ur.user_id = ?"
        );
        $stmt->execute([$_SESSION['user_id']]);
        $perms = $stmt->fetchAll();
        
        $grouped = [];
        foreach ($perms as $p) {
            $grouped[$p['module']][] = $p['action'];
        }
        $_SESSION['permissions'] = $grouped;
    }
    
    public static function setOtpPending(int $userId): void {
        $_SESSION['otp_pending'] = true;
        $_SESSION['otp_user_id'] = $userId;
    }
    
    public static function isPendingOtp(): bool {
        return isset($_SESSION['otp_pending']) && $_SESSION['otp_pending'] === true;
    }
    
    public static function clearOtpPending(): void {
        unset($_SESSION['otp_pending'], $_SESSION['otp_user_id']);
    }
}
