<?php

namespace App\Services;

use CodeIgniter\Database\BaseConnection;

/**
 * Role-based access control — permissions by role name (no hardcoded role IDs).
 * Optional overrides stored in system_settings as rbac_overrides JSON.
 */
class RbacService
{
    /** @var array<string, list<string>> */
    private const PERMISSIONS = [
        'super_admin' => ['*'],
        'facility_manager' => [
            'dashboard', 'dashboard.kpi', 'helpdesk', 'workorders', 'job-cards', 'facilities', 'assets',
            'employees', 'inventory', 'procurement', 'vendors', 'compliance', 'utility', 'reports',
            'reports.finance', 'reports.kpi', 'finance.contracts', 'finance.petty_cash', 'finance.reimbursements',
            'estimations', 'costing', 'ai', 'settings.users', 'settings.activity', 'notifications',
        ],
        'property_manager' => [
            'dashboard', 'dashboard.kpi', 'helpdesk', 'workorders', 'job-cards', 'facilities', 'assets',
            'employees', 'inventory', 'compliance', 'utility', 'reports', 'reports.kpi',
            'finance.petty_cash', 'finance.reimbursements', 'estimations', 'notifications', 'profile',
        ],
        'supervisor' => [
            'dashboard', 'helpdesk', 'workorders', 'job-cards', 'employees', 'reports', 'profile', 'notifications',
        ],
        'qa_inspector' => [
            'dashboard', 'workorders', 'job-cards', 'reports', 'profile', 'notifications',
        ],
        'technician' => [
            'dashboard', 'workorders', 'job-cards', 'inventory', 'profile', 'notifications',
            'finance.reimbursements.create', 'finance.reimbursements.view', 'finance.petty_cash.create',
        ],
        'finance_manager' => [
            'dashboard', 'dashboard.kpi', 'finance', 'finance.invoices', 'finance.expenses',
            'finance.petty_cash', 'finance.reimbursements', 'finance.contracts',
            'finance.ledger', 'finance.payments', 'reports', 'reports.finance', 'reports.kpi', 'profile', 'notifications',
        ],
        'finance_user' => [
            'dashboard', 'finance', 'finance.invoices', 'finance.expenses',
            'finance.petty_cash', 'finance.reimbursements', 'profile', 'notifications',
        ],
        'procurement_officer' => [
            'dashboard', 'procurement', 'inventory', 'vendors', 'reports', 'reports.procurement', 'profile', 'notifications',
        ],
        'client' => [
            'dashboard', 'helpdesk', 'profile', 'notifications', 'finance.invoices',
        ],
    ];

    /** @var array<string, string> */
    public const PERMISSION_LABELS = [
        'dashboard' => 'Dashboard',
        'dashboard.kpi' => 'KPI Analytics',
        'helpdesk' => 'Help Desk',
        'workorders' => 'Work Orders',
        'job-cards' => 'Job Cards',
        'facilities' => 'Facilities',
        'assets' => 'Assets',
        'employees' => 'Employees',
        'inventory' => 'Inventory',
        'procurement' => 'Procurement',
        'vendors' => 'Vendors',
        'finance' => 'Finance Overview',
        'finance.invoices' => 'Invoices',
        'finance.expenses' => 'Expenses',
        'finance.petty_cash' => 'Petty Cash',
        'finance.reimbursements' => 'Reimbursements',
        'finance.contracts' => 'Contracts',
        'finance.ledger' => 'Ledger',
        'finance.payments' => 'Payments',
        'reports' => 'Reports',
        'reports.finance' => 'Finance Reports',
        'reports.kpi' => 'KPI Reports',
        'reports.procurement' => 'Procurement Reports',
        'compliance' => 'Compliance',
        'utility' => 'Utility & Energy',
        'estimations' => 'Estimations',
        'costing' => 'Maintenance Costing',
        'ai' => 'AI Insights',
        'settings.users' => 'Users & Settings',
        'settings.companies' => 'Companies',
        'settings.roles' => 'Roles & Permissions',
        'settings.workflow' => 'Workflow Config',
        'settings.activity' => 'Activity Log',
        'settings.login_history' => 'Login History',
        'notifications' => 'Notifications',
        'profile' => 'Profile',
    ];

    private ?array $overrides = null;

    public function __construct(private ?BaseConnection $db = null)
    {
    }

    /** @return list<string> */
    public static function allPermissionKeys(): array
    {
        return array_keys(self::PERMISSION_LABELS);
    }

    /** @return array<string, list<string>> */
    public function permissionsMap(): array
    {
        $map = self::PERMISSIONS;
        $overrides = $this->loadOverrides();
        foreach ($overrides as $role => $perms) {
            if (is_array($perms)) {
                $map[$role] = $perms;
            }
        }

        return $map;
    }

    public function can(string $role, string $permission): bool
    {
        $perms = $this->permissionsMap()[$role] ?? $this->permissionsMap()['client'];

        if (in_array('*', $perms, true)) {
            return true;
        }

        foreach ($perms as $p) {
            if ($p === $permission || str_starts_with($permission, $p . '.')) {
                return true;
            }
        }

        return false;
    }

    /** @return list<string> */
    public function permissionsFor(string $role): array
    {
        return $this->permissionsMap()[$role] ?? $this->permissionsMap()['client'];
    }

    /** @param array<string, list<string>> $map */
    public function saveOverrides(array $map): void
    {
        if (!$this->db || !$this->db->tableExists('system_settings')) {
            return;
        }
        $json = json_encode($map);
        $exists = $this->db->table('system_settings')->where('setting_key', 'rbac_overrides')->countAllResults();
        if ($exists) {
            $this->db->table('system_settings')->where('setting_key', 'rbac_overrides')->update(['setting_value' => $json]);
        } else {
            $this->db->table('system_settings')->insert(['setting_key' => 'rbac_overrides', 'setting_value' => $json]);
        }
        $this->overrides = null;
        cache()->delete('system_settings');
    }

    public function canAccessRoute(string $role, string $uri): bool
    {
        $uri = trim($uri, '/');

        $routePermission = match (true) {
            $uri === '' || $uri === 'dashboard' => 'dashboard',
            str_starts_with($uri, 'dashboard/kpi') => 'dashboard.kpi',
            str_starts_with($uri, 'helpdesk') => 'helpdesk',
            str_starts_with($uri, 'workorders') => 'workorders',
            str_starts_with($uri, 'job-cards') => 'job-cards',
            str_starts_with($uri, 'facilities') || str_starts_with($uri, 'units') => 'facilities',
            str_starts_with($uri, 'asset-register') => 'assets',
            str_starts_with($uri, 'employees') => 'employees',
            str_starts_with($uri, 'inventory') => 'inventory',
            str_starts_with($uri, 'procurement') => 'procurement',
            str_starts_with($uri, 'vendors') => 'vendors',
            str_starts_with($uri, 'estimations') => 'estimations',
            str_starts_with($uri, 'costing') => 'costing',
            str_starts_with($uri, 'ai') => 'ai',
            str_starts_with($uri, 'finance/ledger') => 'finance.ledger',
            str_starts_with($uri, 'finance/payments') => 'finance.payments',
            str_starts_with($uri, 'finance/petty-cash/create') => 'finance.petty_cash',
            str_starts_with($uri, 'finance/petty-cash') => 'finance.petty_cash',
            str_starts_with($uri, 'finance/reimbursements/create') => 'finance.reimbursements.create',
            str_starts_with($uri, 'finance/reimbursements') => 'finance.reimbursements',
            str_starts_with($uri, 'finance/invoices') => 'finance.invoices',
            str_starts_with($uri, 'finance/contracts') => 'finance.contracts',
            str_starts_with($uri, 'finance/expenses') => 'finance.expenses',
            str_starts_with($uri, 'finance') => 'finance',
            str_starts_with($uri, 'reports/kpi') => 'reports.kpi',
            str_starts_with($uri, 'reports/finance') => 'reports.finance',
            str_starts_with($uri, 'reports/procurement') => 'reports.procurement',
            str_starts_with($uri, 'reports') => 'reports',
            str_starts_with($uri, 'compliance') => 'compliance',
            str_starts_with($uri, 'utility') => 'utility',
            str_starts_with($uri, 'settings/companies') => 'settings.companies',
            str_starts_with($uri, 'settings/roles') => 'settings.roles',
            str_starts_with($uri, 'settings/workflow') => 'settings.workflow',
            str_starts_with($uri, 'settings/activity-log') => 'settings.activity',
            str_starts_with($uri, 'settings/login-history') => 'settings.login_history',
            str_starts_with($uri, 'settings') => 'settings.users',
            str_starts_with($uri, 'notifications') => 'notifications',
            str_starts_with($uri, 'profile') => 'profile',
            str_starts_with($uri, 'ajax') => 'dashboard',
            default => 'dashboard',
        };

        return $this->can($role, $routePermission);
    }

    /** @return array<string, list<string>> */
    private function loadOverrides(): array
    {
        if ($this->overrides !== null) {
            return $this->overrides;
        }
        $this->overrides = [];
        if (!$this->db || !$this->db->tableExists('system_settings')) {
            return $this->overrides;
        }
        $row = $this->db->table('system_settings')->where('setting_key', 'rbac_overrides')->get()->getRowArray();
        if ($row && !empty($row['setting_value'])) {
            $decoded = json_decode($row['setting_value'], true);
            if (is_array($decoded)) {
                $this->overrides = $decoded;
            }
        }

        return $this->overrides;
    }
}
