<?php

declare(strict_types=1);

namespace App\Services;

use App\Core\AccessControl;
use App\Core\Auth;

/**
 * DIAR-6B.5-R2.7.1 central visibility, route, case-scope and action policy.
 *
 * Hidden modules are never returned to navigation or views. Controllers use
 * the same policy before loading repositories, while repositories receive the
 * derived case scope so UI hiding cannot become a data-scope bypass.
 */
final class DiarAccessPolicy
{
    private const DEVELOPER_ROLE = 'DIAR_PLATFORM_DEVELOPER';
    private const ELEVATED_DEVELOPER_ROLE = 'DIAR_PLATFORM_DEVELOPER_ELEVATED';
    private const SITE_DEVELOPER_SUPERUSER_ROLE = 'SITE_DEVELOPER_SUPERUSER';

    /** @return array<int,string> */
    public function roleCodes(): array
    {
        $user = Auth::user();
        $roles = is_array($user['access_control']['roles'] ?? null)
            ? $user['access_control']['roles']
            : [];
        $codes = [];
        foreach ($roles as $role) {
            $code = strtoupper(trim((string)($role['role_code'] ?? '')));
            if ($code !== '' && !in_array($code, $codes, true)) {
                $codes[] = $code;
            }
        }
        return $codes;
    }

    public function hasRole(string $roleCode): bool
    {
        return in_array(strtoupper(trim($roleCode)), $this->roleCodes(), true);
    }

    /** @param array<int,string> $roleCodes */
    public function hasAnyRole(array $roleCodes): bool
    {
        $wanted = array_map('strtoupper', $roleCodes);
        return count(array_intersect($this->roleCodes(), $wanted)) > 0;
    }

    public function isDeveloper(): bool
    {
        return $this->hasAnyRole([self::DEVELOPER_ROLE, self::ELEVATED_DEVELOPER_ROLE, self::SITE_DEVELOPER_SUPERUSER_ROLE]);
    }

    public function isElevatedDeveloper(): bool
    {
        return $this->hasAnyRole([self::ELEVATED_DEVELOPER_ROLE, self::SITE_DEVELOPER_SUPERUSER_ROLE]);
    }

    public function isSystemAdministrator(): bool
    {
        return $this->hasAnyRole(['SITE_ADMIN', self::SITE_DEVELOPER_SUPERUSER_ROLE]);
    }

    public function canViewModule(string $module): bool
    {
        if ($this->isDeveloper()) {
            return true;
        }

        $rolesByModule = [
            'executive' => ['DIAR_EXECUTIVE_VIEWER','DIAR_AUDIT_DIRECTOR','DIAR_READ_ONLY_AUDITOR'],
            'statistics' => ['DIAR_AUDIT_DIRECTOR','DIAR_STAT_ANALYST','DIAR_READ_ONLY_AUDITOR'],
            'cases' => ['DIAR_AUDIT_DIRECTOR','DIAR_INV_SUPERVISOR','DIAR_READ_ONLY_AUDITOR'],
            'investigation' => ['DIAR_AUDIT_DIRECTOR','DIAR_INV_SUPERVISOR','DIAR_INVESTIGATOR','DIAR_READ_ONLY_AUDITOR'],
            'reports' => ['DIAR_EXECUTIVE_VIEWER','DIAR_AUDIT_DIRECTOR','DIAR_STAT_ANALYST','DIAR_READ_ONLY_AUDITOR'],
            'governance' => ['SITE_ADMIN'],
        ];

        return $this->hasAnyRole((array)($rolesByModule[$module] ?? []));
    }

    public function canOpenPortal(): bool
    {
        foreach (['executive','statistics','cases','investigation','reports','governance'] as $module) {
            if ($this->canViewModule($module)) {
                return true;
            }
        }
        return false;
    }

    public function canOpenRoute(string $route): bool
    {
        if ($this->isDeveloper()) {
            return true;
        }
        $route = strtolower(trim($route));
        $moduleByRoute = [
            'diar-portal' => 'portal',
            'diar-executive-overview' => 'executive',
            'diar-statistics' => 'statistics',
            'diar-daily-facts' => 'statistics',
            'diar-movement-dictionary' => 'statistics',
            'diar-statistical-profiles' => 'statistics',
            'diar-cases' => 'cases',
            'diar-anomaly-candidates' => 'cases',
            'diar-case-evidence' => 'cases_or_investigation',
            'diar-investigation-workspace' => 'investigation',
            'diar-investigations' => 'investigation',
            'diar-investigation' => 'investigation',
            'diar-reports' => 'reports',
            'diar-report-excel' => 'reports',
            'diar-report-powerpoint' => 'reports',
            'diar-report-download' => 'reports',
            'diar-governance' => 'governance',
            'diar-rules' => 'governance',
            'diar-engine-runs' => 'governance',
            'diar-command-center' => 'governance',
            'access-control' => 'governance',
        ];
        $module = (string)($moduleByRoute[$route] ?? '');
        if ($module === 'portal') {
            return $this->canOpenPortal();
        }
        if ($module === 'cases_or_investigation') {
            return $this->canViewModule('cases') || $this->canViewModule('investigation');
        }
        return $module !== '' && $this->canViewModule($module);
    }

    public function homeRoute(): string
    {
        if ($this->hasRole(self::SITE_DEVELOPER_SUPERUSER_ROLE)) {
            return 'dashboard';
        }
        if ($this->isDeveloper()) {
            return 'diar-portal';
        }
        $priority = [
            'DIAR_EXECUTIVE_VIEWER' => 'diar-executive-overview',
            'DIAR_AUDIT_DIRECTOR' => 'diar-investigations',
            'DIAR_INV_SUPERVISOR' => 'diar-investigations',
            'DIAR_INVESTIGATOR' => 'diar-investigations',
            'DIAR_STAT_ANALYST' => 'diar-statistics',
            'DIAR_READ_ONLY_AUDITOR' => 'diar-executive-overview',
            'SITE_ADMIN' => 'diar-governance',
        ];
        foreach ($priority as $role => $route) {
            if ($this->hasRole($role)) {
                return $route;
            }
        }
        return 'dashboard';
    }

    public function redirectHiddenRoute(): void
    {
        \redirect(\url_to($this->homeRoute()));
    }

    /** @return array{mode:string,username:string} */
    public function caseScope(): array
    {
        if ($this->isDeveloper() || $this->hasAnyRole([
            'DIAR_AUDIT_DIRECTOR','DIAR_INV_SUPERVISOR','DIAR_READ_ONLY_AUDITOR'
        ])) {
            return ['mode' => 'all', 'username' => ''];
        }
        if ($this->hasRole('DIAR_INVESTIGATOR')) {
            return ['mode' => 'assigned', 'username' => trim((string)Auth::name())];
        }
        return ['mode' => 'none', 'username' => ''];
    }

    /** @param array<string,mixed> $case */
    public function canViewCase(array $case): bool
    {
        $scope = $this->caseScope();
        if ($scope['mode'] === 'all') {
            return true;
        }
        if ($scope['mode'] !== 'assigned') {
            return false;
        }
        $assigned = trim((string)($case['assigned_to'] ?? ''));
        return $assigned !== '' && $scope['username'] !== ''
            && strcasecmp($assigned, $scope['username']) === 0;
    }

    /** @param array<string,mixed> $case */
    public function canPerform(string $action, array $case = []): bool
    {
        $action = strtolower(trim($action));
        if ($this->isElevatedDeveloper()) {
            return true;
        }
        if ($this->isDeveloper() || $this->hasRole('DIAR_READ_ONLY_AUDITOR')) {
            return false;
        }
        if ($this->hasRole('DIAR_AUDIT_DIRECTOR')) {
            return in_array($action, [
                'assign','review','evidence','request_information','propose_finding',
                'supervisor_review','management_approve','corrective_action','close','reopen','escalate'
            ], true);
        }
        if ($this->hasRole('DIAR_INV_SUPERVISOR')) {
            return in_array($action, [
                'assign','review','evidence','request_information','propose_finding',
                'supervisor_review','corrective_action','close','escalate'
            ], true);
        }
        if ($this->hasRole('DIAR_INVESTIGATOR') && $this->canViewCase($case)) {
            return in_array($action, [
                'review','evidence','request_information','propose_finding','escalate'
            ], true);
        }
        if ($this->isSystemAdministrator()) {
            return false;
        }
        return false;
    }

    public function canShowRoleMatrix(): bool
    {
        return $this->isDeveloper() || $this->isSystemAdministrator();
    }

    public function isReadOnlySession(): bool
    {
        return $this->hasRole('DIAR_READ_ONLY_AUDITOR')
            || ($this->isDeveloper() && !$this->isElevatedDeveloper());
    }

    public function developerBadge(): string
    {
        if ($this->hasRole(self::SITE_DEVELOPER_SUPERUSER_ROLE)) {
            return current_lang() === 'ar' ? 'مدير الموقع ومطور الاختبار الشامل' : 'Site Developer Full-Test Administrator';
        }
        if ($this->isElevatedDeveloper()) {
            return current_lang() === 'ar' ? 'وضع دعم DIAR الموسع' : 'DIAR Elevated Support';
        }
        if ($this->isDeveloper()) {
            return current_lang() === 'ar' ? 'مطور ومشرف منظومة ذكاء مخاطر الأدوية' : 'Medication Risk Intelligence Developer';
        }
        return '';
    }

    public function allowsPermission(string $permission): bool
    {
        if ($this->isElevatedDeveloper()) {
            return true;
        }
        if ($this->isDeveloper() && in_array($permission, [
            'diar.investigation.assign',
            'diar.investigation.review',
            'diar.investigation.evidence',
            'diar.investigation.request_information',
            'diar.investigation.finding.propose',
            'diar.investigation.supervisor_review',
            'diar.investigation.management_approve',
            'diar.investigation.corrective_action',
            'diar.investigation.escalate',
            'diar.investigation.close',
            'diar.investigation.reopen',
        ], true)) {
            return false;
        }
        return AccessControl::allows($permission);
    }
}
