<?php

namespace App\Actions\Applications;

use App\Enums\ApplicationStatus;
use App\Enums\ApplicationStep;
use App\Models\Applicant;
use App\Models\Application;
use App\Models\Intake;
use App\Services\Admissions\ApplicationStatusService;
use App\Services\Admissions\ReferenceNumberService;
use App\Services\AuditLogger;
use Illuminate\Support\Facades\DB;
use RuntimeException;

/**
 * Creates a draft application for an applicant against an open intake.
 *
 * An applicant may only hold one live application per intake, so calling this
 * twice returns the existing draft rather than creating a duplicate.
 */
class StartApplication
{
    public function __construct(
        protected ReferenceNumberService $references,
        protected ApplicationStatusService $status,
        protected AuditLogger $audit,
    ) {}

    public function execute(Applicant $applicant, ?Intake $intake = null): Application
    {
        $intake ??= Intake::current();

        if (! $intake) {
            throw new RuntimeException('There is no intake currently accepting applications.');
        }

        if (! $intake->isAcceptingApplications()) {
            throw new RuntimeException("Applications for {$intake->name} are not open.");
        }

        $existing = $applicant->applications()
            ->where('intake_id', $intake->id)
            ->whereNotIn('status', [ApplicationStatus::Withdrawn, ApplicationStatus::Rejected])
            ->first();

        if ($existing) {
            return $existing;
        }

        $application = DB::transaction(function () use ($applicant, $intake) {
            return Application::create([
                'application_number' => $this->references->applicationNumber($intake->year),
                'applicant_id' => $applicant->id,
                'intake_id' => $intake->id,
                'status' => ApplicationStatus::Draft,
                'current_step' => ApplicationStep::first(),
                'completed_steps' => [],
            ]);
        });

        $this->status->recordInitial($application);

        $this->audit->log('application.started', $application, [], [
            'application_number' => $application->application_number,
            'intake' => $intake->name,
        ]);

        return $application;
    }
}
