<?php

namespace App\Models\Scopes;

use App\Services\CurrentContext;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Support\Facades\Auth;

/**
 * Branch scoping for models where a NULL branch_id is a deliberate "applies
 * to every branch" value (e.g. ProductBundle, Voucher) rather than "no
 * branch set" — a plain {@see BranchScope} `where branch_id = X` would
 * wrongly exclude those global rows for a branch-restricted user. Global
 * (NULL) rows always remain visible; branch-specific rows are restricted
 * exactly like BranchScope.
 *
 * Bypass when needed: `Model::withoutGlobalScope(NullableBranchScope::class)`.
 */
class NullableBranchScope implements Scope
{
    public function apply(Builder $builder, Model $model): void
    {
        if (! Auth::check()) {
            return;
        }

        $context = app(CurrentContext::class);
        $table = $model->getTable();
        $column = $table.'.branch_id';

        if ($context->isAllBranches()) {
            $accessible = $context->accessibleBranchIds();
            if ($accessible !== null) {
                $builder->where(fn ($q) => $q->whereNull($column)->orWhereIn($column, $accessible));
            }

            return;
        }

        if ($context->hasUnrestrictedBranchAccess() && ! $context->hasExplicitBranch()) {
            return;
        }

        $branchId = $context->branchId();
        if ($branchId === null) {
            // No resolvable single branch: global (NULL) rows are still for
            // everyone, but a branch-specific row can't be attributed safely.
            $builder->whereNull($column);

            return;
        }

        $builder->where(fn ($q) => $q->whereNull($column)->orWhere($column, $branchId));
    }
}
