<?php

namespace App\Http\Controllers\Api\V1\Applicants;

use App\Domain\Applicants\Enums\ApplicantStatus;
use App\Domain\Applicants\Models\Applicant;
use App\Domain\Applicants\Policies\ApplicantPolicy;
use App\Domain\Applicants\Services\ApplicantService;
use App\Domain\Applicants\Services\DuplicateDetector;
use App\Domain\Identity\Services\ScopeGuard;
use App\Http\Controllers\Controller;
use App\Http\Requests\Applicants\StoreApplicantRequest;
use App\Http\Requests\Applicants\UpdateApplicantRequest;
use App\Http\Resources\ApplicantResource;
use App\Http\Resources\DuplicateMatchResource;
use App\Support\ApiResponse;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class ApplicantController extends Controller
{
    public function __construct(
        private readonly ApplicantService $applicants,
        private readonly DuplicateDetector $duplicates,
        private readonly ScopeGuard $scopes,
    ) {}

    public function index(Request $request): JsonResponse
    {
        $this->authorize('viewAny', Applicant::class);

        $query = Applicant::query()->with([
            'agent:id,uuid,name,agent_code',
            'branch:id,uuid,name',
            'jobDemand:id,uuid,demand_code,job_title',
            'currentStage',
        ]);

        $this->scopes->apply($query, $request->user(), 'applicant.view', ApplicantPolicy::OWNER_COLUMNS);

        $applicants = $query
            ->when($request->filled('search'), function ($builder) use ($request) {
                $search = '%'.$request->string('search').'%';
                $builder->where(fn ($q) => $q
                    ->where('full_name', 'like', $search)
                    ->orWhere('reference_no', 'like', $search)
                    ->orWhere('mobile', 'like', $search)
                    ->orWhere('passport_number', 'like', $search)
                    ->orWhere('national_id', 'like', $search));
            })
            ->when($request->filled('status'), fn ($b) => $b->where('status', $request->string('status')))
            ->when($request->filled('agent_id'), fn ($b) => $b->whereHas(
                'agent', fn ($q) => $q->where('uuid', $request->string('agent_id'))
            ))
            ->when($request->filled('job_demand_id'), fn ($b) => $b->whereHas(
                'jobDemand', fn ($q) => $q->where('uuid', $request->string('job_demand_id'))
            ))
            ->when($request->boolean('active_only'), fn ($b) => $b->active())
            ->when($request->boolean('unverified_only'), fn ($b) => $b->whereNull('verified_at'))
            ->latest('id')
            ->paginate($request->integer('per_page', 25));

        return ApiResponse::success(
            ApplicantResource::collection($applicants),
            meta: [
                'statuses' => array_map(
                    fn (ApplicantStatus $status) => ['value' => $status->value, 'label' => $status->label()],
                    ApplicantStatus::cases(),
                ),
            ],
        );
    }

    public function show(Applicant $applicant): JsonResponse
    {
        $this->authorize('view', $applicant);

        $applicant->load([
            'agent:id,uuid,name,agent_code',
            'branch:id,uuid,name',
            'assignedStaff:id,uuid,name',
            'employer:id,uuid,company_name',
            'jobDemand',
            'mergedInto:id,uuid,reference_no,full_name',
            'pipeline',
            'currentStage',
        ]);

        return ApiResponse::success(new ApplicantResource($applicant));
    }

    public function store(StoreApplicantRequest $request): JsonResponse
    {
        $this->authorize('create', Applicant::class);

        $attributes = $request->modelAttributes();
        $attributes['company_id'] = $request->user()->company_id;
        $attributes['branch_id'] ??= $request->user()->branch_id;

        // Overriding a hard duplicate is a permissioned decision, not a checkbox
        // anyone can tick.
        $allowDuplicate = $request->allowsDuplicate()
            && $request->user()->can('overrideDuplicate', Applicant::class);

        $applicant = $this->applicants->create($attributes, $request->user(), $allowDuplicate);

        return ApiResponse::success(
            new ApplicantResource($applicant->load(['agent:id,uuid,name,agent_code', 'branch:id,uuid,name'])),
            'Applicant registered successfully.',
            status: 201,
        );
    }

    public function update(UpdateApplicantRequest $request, Applicant $applicant): JsonResponse
    {
        $this->authorize('update', $applicant);

        $allowDuplicate = $request->allowsDuplicate()
            && $request->user()->can('overrideDuplicate', Applicant::class);

        $applicant = $this->applicants->update(
            $applicant,
            $request->modelAttributes(),
            $request->user(),
            $allowDuplicate,
        );

        return ApiResponse::success(
            new ApplicantResource($applicant->fresh()->load(['agent:id,uuid,name,agent_code', 'branch:id,uuid,name'])),
            'Applicant updated successfully.',
        );
    }

    /**
     * Duplicate pre-check, called from the registration form before saving so
     * the warning appears while the data is still on screen (§9.2).
     */
    public function checkDuplicates(Request $request): JsonResponse
    {
        $this->authorize('create', Applicant::class);

        $matches = $this->duplicates->check(
            $request->user()->company_id,
            $request->only(['national_id', 'passport_number', 'mobile', 'email', 'full_name', 'date_of_birth']),
        );

        return ApiResponse::success(
            DuplicateMatchResource::collection($matches),
            meta: [
                'has_hard_match' => $matches->contains(fn ($m) => $m['level'] === DuplicateDetector::HARD),
                'can_override' => $request->user()->can('overrideDuplicate', Applicant::class),
            ],
        );
    }
}
