<?php

namespace App\Http\Controllers\Admin;

use App\Actions\Admissions\AdmitApplicant;
use App\Http\Controllers\Controller;
use App\Jobs\GenerateAdmissionDocuments;
use App\Models\AdmissionRecord;
use App\Models\Application;
use App\Models\Intake;
use App\Models\Programme;
use App\Services\AuditLogger;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpFoundation\StreamedResponse;

class AdmissionController extends Controller
{
    public function __construct(protected AuditLogger $audit) {}

    public function index(Request $request): View
    {
        $intakeId = $request->integer('intake') ?: Intake::current()?->id;

        return view('admin.admissions.index', [
            'records' => AdmissionRecord::query()
                ->with(['application.applicant', 'programme.school', 'intake', 'admittedBy'])
                ->when($intakeId, fn ($q) => $q->where('intake_id', $intakeId))
                ->latest('admitted_at')
                ->paginate(25)
                ->withQueryString(),
            'intakes' => Intake::orderByDesc('year')->get(['id', 'name']),
            'selectedIntake' => $intakeId,
        ]);
    }

    public function admit(Request $request, Application $application, AdmitApplicant $action): RedirectResponse
    {
        $data = $request->validate([
            'programme_id' => ['nullable', 'integer', 'exists:programmes,id'],
            'conditions' => ['nullable', 'string', 'max:2000'],
            'reporting_date' => ['nullable', 'date'],
            'confirm' => ['accepted'],
        ], [
            'confirm.accepted' => 'Please confirm this admission decision.',
        ]);

        try {
            $record = $action->execute(
                application: $application,
                actor: $request->user(),
                programme: isset($data['programme_id']) ? Programme::find($data['programme_id']) : null,
                conditions: $data['conditions'] ?? null,
                reportingDate: $data['reporting_date'] ?? null,
            );
        } catch (ValidationException $e) {
            return back()->withErrors($e->errors());
        }

        return back()->with(
            'status',
            "Admitted. Admission number {$record->admission_number} issued; documents are being generated."
        );
    }

    public function regenerate(Request $request, AdmissionRecord $admissionRecord): RedirectResponse
    {
        GenerateAdmissionDocuments::dispatch($admissionRecord->application_id, $request->user()->id);

        $this->audit->log('admission.documents_regenerated', $admissionRecord);

        return back()->with('status', 'Admission documents are being regenerated.');
    }

    public function letter(AdmissionRecord $admissionRecord): StreamedResponse
    {
        $document = $admissionRecord->application
            ->generatedDocuments()
            ->where('document_type', \App\Models\GeneratedDocument::TYPE_ADMISSION_LETTER)
            ->latest('version')
            ->first();

        abort_unless($document, 404, 'The admission letter has not been generated yet.');

        $disk = Storage::disk($document->disk);

        abort_unless($disk->exists($document->storage_path), 404);

        $this->audit->log(AuditLogger::DOCUMENT_DOWNLOADED, $admissionRecord, [], [
            'document_type' => 'admission_letter',
        ]);

        return $disk->download($document->storage_path, $document->filename);
    }
}
