<?php

namespace App\Domain\Applicants\Policies;

use App\Domain\Applicants\Models\Applicant;
use App\Domain\Identity\Models\User;
use App\Domain\Identity\Services\ScopeGuard;

/**
 * Ownership of an applicant file is satisfied by the staff member it is
 * assigned to, the user who registered it, or the applicant's own portal login.
 */
class ApplicantPolicy
{
    /** @var array<int, string> */
    public const OWNER_COLUMNS = ['assigned_to', 'created_by', 'user_id'];

    public function __construct(private readonly ScopeGuard $scopes) {}

    public function viewAny(User $user): bool
    {
        return $user->can('applicant.view');
    }

    public function view(User $user, Applicant $applicant): bool
    {
        return $user->can('applicant.view') && $this->owns($user, 'applicant.view', $applicant);
    }

    public function create(User $user): bool
    {
        return $user->can('applicant.create');
    }

    public function update(User $user, Applicant $applicant): bool
    {
        // A merged tombstone is history; it is not edited further.
        return $user->can('applicant.update')
            && $applicant->merged_into_id === null
            && $this->owns($user, 'applicant.update', $applicant);
    }

    public function changeStage(User $user, Applicant $applicant): bool
    {
        return $user->can('applicant.change_stage') && $this->owns($user, 'applicant.change_stage', $applicant);
    }

    public function assignAgent(User $user, Applicant $applicant): bool
    {
        return $user->can('applicant.assign_agent') && $this->owns($user, 'applicant.assign_agent', $applicant);
    }

    public function assignStaff(User $user, Applicant $applicant): bool
    {
        return $user->can('applicant.assign_staff') && $this->owns($user, 'applicant.assign_staff', $applicant);
    }

    public function merge(User $user, Applicant $applicant): bool
    {
        return $user->can('applicant.merge') && $this->owns($user, 'applicant.merge', $applicant);
    }

    /** Saving past a duplicate warning is a deliberate, permissioned override. */
    public function overrideDuplicate(User $user): bool
    {
        return $user->can('applicant.merge') || $user->can('applicant.override_stage');
    }

    public function viewSensitive(User $user, Applicant $applicant): bool
    {
        return $user->can('applicant.view_sensitive') && $this->owns($user, 'applicant.view_sensitive', $applicant);
    }

    private function owns(User $user, string $permission, Applicant $applicant): bool
    {
        return $this->scopes->allows($user, $permission, $applicant, self::OWNER_COLUMNS);
    }
}
