<?php

namespace App\Models\Scopes;

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 ParentBranchScope implements Scope
{
    /**
     * @param array<int, string> $routeParameters
     */
    public function __construct(
        private string $parentTable,
        private string $foreignKey,
        private string $parentKey = 'id',
        private array $routeParameters = [],
    ) {
    }

    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($this->foreignKey),
            fn ($query) => $query
                ->select($this->parentKey)
                ->from($this->parentTable)
                ->whereIn('branch_id', $branchIds)
        );
    }

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

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

        $parameters = array_values(array_unique(array_merge(
            [Str::snake(class_basename($model))],
            $this->routeParameters,
        )));

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

        return false;
    }
}
