<?php

declare(strict_types=1);

namespace App\Http\Requests\Concerns;

use App\Enums\UserRole;
use App\Models\Branch;
use App\Models\User;
use Illuminate\Validation\Validator;

trait ValidatesUserScope
{
    /**
     * Schema-doc invariant: super_admin ⇒ both scopes null; region_admin ⇒
     * region_id set, branch_id null; branch_admin/data_clerk ⇒ branch_id set;
     * viewer ⇒ exactly one of region_id/branch_id set. Plus: a region_admin
     * may only manage branch-level roles within their own region.
     */
    protected function withUserScopeValidation(Validator $validator): void
    {
        $validator->after(function (Validator $validator) {
            $role = $this->enumRole();
            $regionId = $this->input('region_id');
            $branchId = $this->input('branch_id');

            if ($role === null) {
                return;
            }

            $this->validateRoleScopeCombination($validator, $role, $regionId, $branchId);
            $this->validateActingUserRestriction($validator, $role, $regionId, $branchId);
        });
    }

    private function enumRole(): ?UserRole
    {
        return UserRole::tryFrom((string) $this->input('role'));
    }

    private function validateRoleScopeCombination(Validator $validator, UserRole $role, mixed $regionId, mixed $branchId): void
    {
        match ($role) {
            UserRole::SuperAdmin => $this->requireNullScopes($validator, $regionId, $branchId),
            UserRole::RegionAdmin => $this->requireRegionOnly($validator, $regionId, $branchId),
            UserRole::BranchAdmin, UserRole::DataClerk => $this->requireBranchOnly($validator, $regionId, $branchId),
            UserRole::Viewer => $this->requireExactlyOneScope($validator, $regionId, $branchId),
        };
    }

    private function requireNullScopes(Validator $validator, mixed $regionId, mixed $branchId): void
    {
        if ($regionId !== null || $branchId !== null) {
            $validator->errors()->add('role', 'super_admin must not have a region_id or branch_id.');
        }
    }

    private function requireRegionOnly(Validator $validator, mixed $regionId, mixed $branchId): void
    {
        if ($regionId === null) {
            $validator->errors()->add('region_id', 'region_admin requires a region_id.');
        }
        if ($branchId !== null) {
            $validator->errors()->add('branch_id', 'region_admin must not have a branch_id.');
        }
    }

    private function requireBranchOnly(Validator $validator, mixed $regionId, mixed $branchId): void
    {
        if ($branchId === null) {
            $validator->errors()->add('branch_id', 'This role requires a branch_id.');
        }
        if ($regionId !== null) {
            $validator->errors()->add('region_id', 'This role must not have a region_id.');
        }
    }

    private function requireExactlyOneScope(Validator $validator, mixed $regionId, mixed $branchId): void
    {
        $set = array_filter([$regionId, $branchId], fn ($v) => $v !== null);

        if (count($set) !== 1) {
            $validator->errors()->add('role', 'viewer requires exactly one of region_id or branch_id.');
        }
    }

    private function validateActingUserRestriction(Validator $validator, UserRole $role, mixed $regionId, mixed $branchId): void
    {
        /** @var User $actingUser */
        $actingUser = $this->user();

        if ($actingUser->role !== UserRole::RegionAdmin) {
            return;
        }

        if (in_array($role, [UserRole::SuperAdmin, UserRole::RegionAdmin], true)) {
            $validator->errors()->add('role', 'region_admin may only create/manage branch-level roles.');

            return;
        }

        if ($regionId !== null && (int) $regionId !== $actingUser->region_id) {
            $validator->errors()->add('region_id', 'You may only manage users within your own region.');
        }

        if ($branchId !== null) {
            $branchRegionId = Branch::query()->where('id', $branchId)->value('region_id');

            if ($branchRegionId !== $actingUser->region_id) {
                $validator->errors()->add('branch_id', 'You may only manage users within your own region.');
            }
        }
    }
}
