<?php

namespace App\Actions\Applications;

use App\Enums\ApplicationStep;
use App\Models\Application;
use App\Models\DocumentType;

/**
 * The single definition of "ready to submit" (PRD 20).
 *
 * Both the wizard checklist and SubmitApplication read from here, so what the
 * applicant sees and what the server enforces can never drift apart.
 */
class ApplicationValidator
{
    /** @return array<int, string> human-readable reasons the application cannot be submitted */
    public function unmetRequirements(Application $application): array
    {
        return collect($this->checklist($application))
            ->reject(fn (array $item) => $item['met'])
            ->pluck('failure')
            ->values()
            ->all();
    }

    public function isReady(Application $application): bool
    {
        return $this->unmetRequirements($application) === [];
    }

    /**
     * @return array<int, array{label: string, met: bool, failure: string, step: ApplicationStep}>
     */
    public function checklist(Application $application): array
    {
        $application->loadMissing(['applicant.qualifications', 'choices', 'documents', 'payments']);

        $applicant = $application->applicant;
        $documents = $application->documentProgress();

        $checks = [
            [
                'label' => 'Personal information complete',
                'met' => (bool) $applicant?->hasCompletePersonalDetails(),
                'failure' => 'Complete your personal information before submitting.',
                'step' => ApplicationStep::Personal,
            ],
            [
                'label' => 'Contact details complete',
                'met' => (bool) $applicant?->hasCompleteContactDetails(),
                'failure' => 'Add your phone number and address before submitting.',
                'step' => ApplicationStep::Contact,
            ],
            [
                'label' => 'Academic history added',
                'met' => (bool) $applicant?->qualifications->isNotEmpty(),
                'failure' => 'Add at least one academic qualification before submitting.',
                'step' => ApplicationStep::Academic,
            ],
            [
                'label' => 'Programme choice selected',
                'met' => $application->choices->isNotEmpty(),
                'failure' => 'Select at least one programme before submitting.',
                'step' => ApplicationStep::Programme,
            ],
            [
                'label' => sprintf('Required documents uploaded (%d of %d)', $documents['uploaded'], $documents['required']),
                'met' => $documents['uploaded'] >= $documents['required'],
                'failure' => 'Upload all required documents before submitting.',
                'step' => ApplicationStep::Documents,
            ],
            [
                'label' => 'Declaration accepted',
                'met' => (bool) $application->declaration_accepted,
                'failure' => 'Accept the declaration before submitting.',
                'step' => ApplicationStep::Declaration,
            ],
        ];

        if (config('kcu.application.require_payment_before_submission')) {
            $checks[] = [
                'label' => 'Application fee paid',
                'met' => $application->isPaid(),
                'failure' => 'Pay the application fee before submitting.',
                'step' => ApplicationStep::Payment,
            ];
        }

        return $checks;
    }

    /** Required document types still missing from the application. */
    public function missingDocuments(Application $application): array
    {
        $uploaded = $application->documents
            ->where('verification_status', '!==', \App\Enums\VerificationStatus::Rejected)
            ->pluck('document_type')
            ->unique();

        return DocumentType::query()
            ->required()
            ->ordered()
            ->get()
            ->reject(fn (DocumentType $type) => $uploaded->contains($type->slug))
            ->values()
            ->all();
    }
}
