<?php

namespace App\Domain\Shared\Scopes;

use App\Domain\Shared\Context\BranchScopeState;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;

/**
 * Branch isolation for the one model whose branch is genuinely many-valued.
 *
 * Every other branch-owned table answers "which branch?" with a column. A
 * pricing rule answers it with a list: `pricing_rule_branches` is how the
 * wizard targets "this discount applies at ZSC and Tara", and
 * `pricing_rules.branch_id` is the older single-branch column that predates it.
 * A plain BranchScope on the column would hide every rule the wizard has ever
 * created, because the wizard leaves that column null on purpose and puts the
 * targeting in the pivot.
 *
 * So this mirrors the model's own scopeForBranch(): a rule is visible here if
 * it names this branch in either place, or if it names nowhere at all — a rule
 * with no column and no pivot rows targets the whole academy, and an
 * academy-wide discount is not another branch's data.
 */
class PricingRuleBranchScope implements Scope
{
    public function apply(Builder $builder, Model $model): void
    {
        $state = app(BranchScopeState::class);

        if (! $state->shouldFilter()) {
            return;
        }

        $branchId = $state->branchId();
        $table = $model->getTable();

        // Grouped, so a later orWhere() on the same builder — a search filter,
        // say — cannot break the OR apart and leak every branch's rules.
        $builder->where(function (Builder $query) use ($branchId, $table) {
            $query->where(function (Builder $untargeted) use ($table) {
                $untargeted->whereNull($table.'.branch_id')
                    ->whereNotExists(function ($e) use ($table) {
                        $e->selectRaw('1')->from('pricing_rule_branches')
                            ->whereColumn('pricing_rule_branches.pricing_rule_id', $table.'.id');
                    });
            });

            if ($branchId) {
                $query->orWhere($table.'.branch_id', $branchId)
                    ->orWhereExists(function ($e) use ($branchId, $table) {
                        $e->selectRaw('1')->from('pricing_rule_branches')
                            ->whereColumn('pricing_rule_branches.pricing_rule_id', $table.'.id')
                            ->where('pricing_rule_branches.branch_id', $branchId);
                    });
            }
        });
    }
}
