<?php

namespace App\Models\Scopes;

use App\Models\DailyClosing;
use App\Models\ExpenseReminder;
use App\Models\FinancialAccount;
use App\Models\LoanPayment;
use App\Models\RecurringExpense;
use App\Models\User;
use App\Services\BranchAccessService;
use App\Services\BranchContext;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;

class BranchScope implements Scope
{
    public function apply(Builder $builder, Model $model): void
    {
        $user = Auth::user();

        if ($user instanceof User) {
            if ($this->isResolvingRouteBinding($model)) {
                return;
            }

            $branchAccess = app(BranchAccessService::class);
            if ($branchAccess->isSystemWide($user)) {
                return;
            }

            $branchIds = $branchAccess->accessibleBranchIds($user);
        } else {
            $context = app(BranchContext::class);
            if ($context->isSystemWide()) {
                return;
            }

            $branchIds = $context->branchIds();
            if ($branchIds === null) {
                $builder->whereRaw('1 = 0');
                return;
            }
        }

        if ($branchIds === []) {
            $builder->whereRaw('1 = 0');
            return;
        }

        $builder->whereIn($model->qualifyColumn('branch_id'), $branchIds);
    }

    private function isResolvingRouteBinding(Model $model): bool
    {
        if (! app()->bound('request')) {
            return false;
        }

        $route = request()->route();
        if (! $route) {
            return false;
        }

        foreach ($this->routeBindingParameters($model) as $parameter) {
            $value = $route->parameter($parameter);
            if (is_scalar($value) && (string) $value !== '') {
                return true;
            }
        }

        return false;
    }

    /** @return array<int, string> */
    private function routeBindingParameters(Model $model): array
    {
        $default = Str::snake(class_basename($model));

        return match ($model::class) {
            LoanPayment::class => [$default, 'payment'],
            FinancialAccount::class => [$default, 'account'],
            DailyClosing::class => [$default, 'dailyClosing'],
            RecurringExpense::class => [$default, 'recurringExpense'],
            ExpenseReminder::class => [$default, 'reminder'],
            default => [$default],
        };
    }
}
