<?php

namespace App\Services\Finance;

use App\Models\User;
use Illuminate\Http\Request;

class FinanceNavService
{
    /** @var list<string> */
    public const MODULE_PERMISSIONS = [
        'finance_view',
        'finance_treasury_view',
        'finance_operational',
        'finance_team_view',
        'finance_self_view',
        'expenses_create_own',
    ];

    public function canAccessModule(?User $user): bool
    {
        return $this->userHasAnyPermission($user, self::MODULE_PERMISSIONS);
    }

    public function hasTreasuryAccess(?User $user): bool
    {
        return $this->userHasAnyPermission($user, ['finance_treasury_view', 'finance_view']);
    }

    public function canUseTreasuryMasters(?User $user): bool
    {
        return $this->hasTreasuryAccess($user);
    }

    public function hasOperationalAccess(?User $user): bool
    {
        return $this->userHasAnyPermission($user, ['finance_operational']);
    }

    public function hasOperationalOrTreasuryAccess(?User $user): bool
    {
        return $this->hasOperationalAccess($user) || $this->hasTreasuryAccess($user);
    }

    public function canViewCompanyExpenses(?User $user): bool
    {
        return $this->userHasAnyPermission($user, [
            'finance_view',
            'finance_treasury_view',
            'finance_operational',
        ]);
    }

    public function homeUrl(?User $user): string
    {
        if (! $user) {
            return route('expenses.index', ['scope' => 'self']);
        }

        if ($this->hasTreasuryAccess($user)) {
            return route('finance.dashboard');
        }

        if ($this->hasOperationalAccess($user)) {
            return route('finance.operational');
        }

        if ($this->userHasAnyPermission($user, ['finance_team_view'])) {
            return route('finance.team');
        }

        return route('finance.self');
    }

    public function zoneLabel(?User $user): ?string
    {
        if (! $user) {
            return null;
        }

        if ($this->hasTreasuryAccess($user)) {
            return 'Company Finance';
        }

        if ($this->hasOperationalAccess($user)) {
            return 'HR Finance';
        }

        if ($this->userHasAnyPermission($user, ['finance_team_view'])) {
            return 'Team Finance';
        }

        if ($this->userHasAnyPermission($user, ['finance_self_view', 'expenses_create_own'])) {
            return 'My Finance';
        }

        return null;
    }

    /**
     * @return list<array<string, mixed>>
     */
    public function primaryTabs(?User $user): array
    {
        if (! $user) {
            return [];
        }

        $tabs = [];
        $seen = [];

        foreach (config('finance_nav.primary', []) as $tab) {
            if (! $this->canSeeTab($user, $tab)) {
                continue;
            }

            $key = $tab['key'] ?? null;
            if ($key && isset($seen[$key])) {
                continue;
            }

            if ($key) {
                $seen[$key] = true;
            }

            $tabs[] = $tab;
        }

        usort($tabs, fn (array $a, array $b) => ($a['sort'] ?? 0) <=> ($b['sort'] ?? 0));

        return $tabs;
    }

    /**
     * @return list<array<string, mixed>>
     */
    public function setupTabs(?User $user): array
    {
        if (! $user) {
            return [];
        }

        $tabs = [];

        foreach (config('finance_nav.setup', []) as $tab) {
            if (! $this->canSeeTab($user, $tab)) {
                continue;
            }

            $tabs[] = $tab;
        }

        return $tabs;
    }

    public function isTabActive(array $tab, ?Request $request = null): bool
    {
        $request ??= request();
        $routeName = $request->route()?->getName() ?? '';

        foreach ($tab['route_is'] ?? [] as $pattern) {
            if (str_ends_with($pattern, '.*')) {
                $prefix = substr($pattern, 0, -2);
                if (str_starts_with($routeName, $prefix)) {
                    return $this->matchesTabScope($tab, $request);
                }
            } elseif ($routeName === $pattern) {
                return $this->matchesTabScope($tab, $request);
            }
        }

        return false;
    }

    public function tabUrl(array $tab): string
    {
        $route = $tab['route'] ?? null;
        if (! $route) {
            return '#';
        }

        return route($route, $tab['route_params'] ?? []);
    }

    public function isMappedFinanceRoute(string $routeName): bool
    {
        return array_key_exists($routeName, config('tenant_permissions.route_permission', []))
            && $this->routeBelongsToFinanceModule($routeName);
    }

    protected function routeBelongsToFinanceModule(string $routeName): bool
    {
        $routeModules = config('tenant_modules.route_module', []);

        foreach ($routeModules as $prefix => $module) {
            if ($module !== 'finance') {
                continue;
            }

            if ($routeName === $prefix || str_starts_with($routeName, $prefix.'.')) {
                return true;
            }
        }

        return false;
    }

    /**
     * @param  array<string, mixed>  $tab
     */
    protected function canSeeTab(User $user, array $tab): bool
    {
        $permissions = $tab['permissions'] ?? [];
        if ($permissions === [] || ! $this->userHasAnyPermission($user, $permissions)) {
            return false;
        }

        $suppressWhen = $tab['suppress_when'] ?? [];
        if ($suppressWhen !== [] && $this->userHasAnyPermission($user, $suppressWhen)) {
            return false;
        }

        return true;
    }

    /**
     * @param  array<string, mixed>  $tab
     */
    protected function matchesTabScope(array $tab, Request $request): bool
    {
        if (array_key_exists('active_when_scope', $tab)) {
            $expected = $tab['active_when_scope'];
            if (($request->query('scope') ?: null) !== $expected) {
                return false;
            }
        }

        if (array_key_exists('active_when_status', $tab)) {
            $expected = $tab['active_when_status'];
            if (($request->query('status') ?: null) !== $expected) {
                return false;
            }
        }

        return true;
    }

    /**
     * @return list<string>
     */
    public function availableExpenseScopes(?User $user): array
    {
        if (! $user) {
            return [];
        }

        $scopes = [];

        if ($this->userHasAnyPermission($user, ['finance_self_view', 'expenses_create_own'])) {
            $scopes[] = 'self';
        }

        if ($user->hasPermission('finance_team_view')) {
            $scopes[] = 'team';
        }

        if ($this->canViewCompanyExpenses($user)) {
            $scopes[] = 'company';
        }

        return $scopes;
    }

    public function expenseScopeLabel(string $scope): string
    {
        return match ($scope) {
            'self' => 'My claims',
            'team' => 'Team expenses',
            'company' => 'Company expenses',
            default => ucfirst($scope),
        };
    }

    /**
     * @return list<array{label: string, url: ?string}>
     */
    public function breadcrumbs(?User $user, ?Request $request = null): array
    {
        $request ??= request();
        $routeName = (string) ($request->route()?->getName() ?? '');
        $scope = (string) ($request->query('scope') ?: '');

        $trail = [
            ['label' => 'Finance', 'url' => $this->homeUrl($user)],
        ];

        if ($routeName === 'finance.self') {
            $trail[] = ['label' => 'My Finance', 'url' => null];

            return $trail;
        }

        if ($routeName === 'finance.team') {
            $trail[] = ['label' => 'Team Finance', 'url' => null];

            return $trail;
        }

        if ($routeName === 'finance.operational') {
            $trail[] = ['label' => 'HR Finance', 'url' => null];

            return $trail;
        }

        if ($routeName === 'finance.my-advances') {
            $trail[] = ['label' => 'My Advances', 'url' => null];

            return $trail;
        }

        if ($routeName === 'finance.dashboard') {
            $trail[] = ['label' => 'Dashboard', 'url' => null];

            return $trail;
        }

        if (str_starts_with($routeName, 'expenses.')) {
            if ($scope === 'self' || ($scope === '' && ! $this->canViewCompanyExpenses($user) && ! $user?->hasPermission('finance_team_view'))) {
                $trail[] = ['label' => 'My claims', 'url' => null];
            } else {
                if ($scope === 'team') {
                    $trail[] = ['label' => 'Team', 'url' => route('finance.team')];
                } elseif ($scope === 'company' || $scope === '') {
                    $trail[] = ['label' => 'Company', 'url' => $this->hasOperationalAccess($user) ? route('finance.operational') : route('finance.dashboard')];
                }
                $trail[] = ['label' => 'Expenses', 'url' => null];
            }

            return $trail;
        }

        if (str_starts_with($routeName, 'pre-payments.')) {
            $trail[] = ['label' => $this->hasTreasuryAccess($user) ? 'Company' : 'HR Finance', 'url' => $this->hasOperationalAccess($user) ? route('finance.operational') : route('finance.dashboard')];
            $trail[] = ['label' => 'Advances', 'url' => null];

            return $trail;
        }

        if (str_starts_with($routeName, 'accounts.') || str_starts_with($routeName, 'deposits.')) {
            $trail[] = ['label' => 'Treasury', 'url' => route('finance.dashboard')];
            $trail[] = ['label' => str_starts_with($routeName, 'accounts.') ? 'Accounts' : 'Deposits', 'url' => null];

            return $trail;
        }

        if (str_starts_with($routeName, 'vendors.') || str_starts_with($routeName, 'payees.') || str_starts_with($routeName, 'payers.') || str_starts_with($routeName, 'deposit-categories.')) {
            $trail[] = ['label' => 'Setup', 'url' => null];

            return $trail;
        }

        return $trail;
    }

    /**
     * @return list<array<string, mixed>>
     */
    public function mobileTabs(?User $user): array
    {
        return collect($this->primaryTabs($user))
            ->map(fn (array $tab) => [
                'key' => $tab['key'] ?? null,
                'label' => $tab['label'] ?? '',
                'route' => $tab['route'] ?? null,
                'url' => $this->tabUrl($tab),
            ])
            ->values()
            ->all();
    }

    /**
     * @param  list<string>  $permissions
     */
    public function userHasAnyPermission(?User $user, array $permissions): bool
    {
        if (! $user) {
            return false;
        }

        if ($user->isSuperAdmin() || $user->isCompanyAccountAdmin()) {
            return true;
        }

        foreach ($permissions as $permission) {
            if ($user->hasPermission($permission)) {
                return true;
            }
        }

        return false;
    }
}
