<?php
declare(strict_types=1);

namespace App\Shared\Services;

use App\Core\App;

final class BranchScopeService
{
    private static ?array $accessibleBranches = null;
    private static ?bool $hasAllBranches = null;

    public static function reset(): void
    {
        self::$accessibleBranches = null;
        self::$hasAllBranches = null;
    }

    public static function getAccessibleBranchIds(): array
    {
        if (self::$accessibleBranches !== null) {
            return self::$accessibleBranches;
        }

        $app = App::getInstance();
        $employee = $app->currentEmployee();

        if (!$employee) {
            self::$accessibleBranches = [];
            return [];
        }

        if (self::hasAllBranches()) {
            $all = $app->db()->select("SELECT id FROM branches WHERE is_active = 1");
            self::$accessibleBranches = array_map(fn($r) => (int) $r['id'], $all);
            return self::$accessibleBranches;
        }

        $rows = $app->db()->select(
            "SELECT branch_id FROM employee_branches WHERE employee_id = ?",
            [(int) $employee->id]
        );

        self::$accessibleBranches = array_map(fn($r) => (int) $r['branch_id'], $rows);

        if (empty(self::$accessibleBranches) && $employee->branch_id) {
            self::$accessibleBranches = [(int) $employee->branch_id];
        }

        return self::$accessibleBranches;
    }

    public static function hasAllBranches(): bool
    {
        if (self::$hasAllBranches !== null) {
            return self::$hasAllBranches;
        }

        $app = App::getInstance();
        $employee = $app->currentEmployee();

        if (!$employee) {
            self::$hasAllBranches = false;
            return false;
        }

        if ($employee->hasPermission('*')) {
            self::$hasAllBranches = true;
            return true;
        }

        $row = $app->db()->selectOne(
            "SELECT 1 FROM employee_roles er
             JOIN roles r ON r.id = er.role_id
             WHERE er.employee_id = ? AND er.is_active = 1
               AND (er.expires_at IS NULL OR er.expires_at > NOW())
               AND r.has_all_branches = 1
             LIMIT 1",
            [(int) $employee->id]
        );

        self::$hasAllBranches = ($row !== null);
        return self::$hasAllBranches;
    }

    /**
     * Returns a SQL WHERE fragment for branch filtering.
     * If user has all branches, returns empty string.
     * Otherwise returns " AND {alias}.{column} IN (?, ?, ...)"
     */
    public static function scopeQuery(string $alias, string $column = 'branch_id'): string
    {
        if (self::hasAllBranches()) {
            return '';
        }

        $ids = self::getAccessibleBranchIds();
        if (empty($ids)) {
            return " AND 1=0";
        }

        $placeholders = implode(',', array_fill(0, count($ids), '?'));
        return " AND {$alias}.{$column} IN ({$placeholders})";
    }

    /**
     * Returns the parameter values to bind for scopeQuery.
     * If user has all branches, returns empty array.
     */
    public static function scopeParams(): array
    {
        if (self::hasAllBranches()) {
            return [];
        }

        return self::getAccessibleBranchIds();
    }

    /**
     * Check if current user can access a specific branch.
     * Throws RuntimeException(403) if denied.
     */
    public static function assertCanAccess(int $branchId): void
    {
        if (self::hasAllBranches()) {
            return;
        }

        $accessible = self::getAccessibleBranchIds();
        if (!in_array($branchId, $accessible, true)) {
            throw new \RuntimeException('ليس لديك صلاحية الوصول لهذا الفرع', 403);
        }
    }

    /**
     * Check if current user can access a specific branch (non-throwing).
     */
    public static function canAccessBranch(int $branchId): bool
    {
        if (self::hasAllBranches()) {
            return true;
        }

        return in_array($branchId, self::getAccessibleBranchIds(), true);
    }
}
