<?php

namespace App\Services\Pdf;

use App\Models\Application;
use App\Models\GeneratedDocument;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

/**
 * Renders the branded PDFs a successful applicant receives (PRD 26).
 *
 * Output is written to the private disk and only ever served through an
 * authorised controller. Re-generating bumps the version rather than
 * overwriting, so a reissued letter never destroys the original.
 */
class DocumentGenerator
{
    protected const DISK = 'private';

    public function admissionLetter(Application $application, ?int $generatedBy = null): GeneratedDocument
    {
        return $this->render(
            $application,
            GeneratedDocument::TYPE_ADMISSION_LETTER,
            'pdf.admission-letter',
            'admission-letter',
            $generatedBy,
        );
    }

    public function joiningInstructions(Application $application, ?int $generatedBy = null): GeneratedDocument
    {
        return $this->render(
            $application,
            GeneratedDocument::TYPE_JOINING_INSTRUCTIONS,
            'pdf.joining-instructions',
            'joining-instructions',
            $generatedBy,
        );
    }

    protected function render(
        Application $application,
        string $type,
        string $view,
        string $filePrefix,
        ?int $generatedBy,
    ): GeneratedDocument {
        $application->loadMissing([
            'applicant',
            'intake',
            'admissionRecord.programme.school',
        ]);

        $version = (int) $application->generatedDocuments()
            ->where('document_type', $type)
            ->max('version') + 1;

        $pdf = Pdf::loadView($view, [
            'application' => $application,
            'applicant' => $application->applicant,
            'record' => $application->admissionRecord,
            'programme' => $application->admissionRecord?->programme,
            'intake' => $application->intake,
            'university' => [
                'name' => setting('university_name'),
                'address' => setting('university_address'),
                'city' => setting('university_city'),
                'country' => setting('university_country'),
                'phone' => setting('university_phone'),
                'email' => setting('university_admissions_email'),
                'motto' => setting('university_motto'),
                'vice_chancellor' => setting('university_vice_chancellor'),
                'logo' => $this->logoData(),
            ],
        ])->setPaper('a4');

        $filename = sprintf(
            '%s-%s-v%d.pdf',
            $filePrefix,
            Str::slug($application->application_number),
            $version,
        );

        $path = "applications/{$application->id}/generated/{$filename}";

        Storage::disk(self::DISK)->put($path, $pdf->output());

        return $application->generatedDocuments()->create([
            'document_type' => $type,
            'filename' => $filename,
            'storage_path' => $path,
            'disk' => self::DISK,
            'version' => $version,
            'file_size' => Storage::disk(self::DISK)->size($path),
            'generated_by' => $generatedBy,
        ]);
    }

    /**
     * dompdf cannot fetch remote assets, so the logo is embedded as a data URI.
     */
    protected function logoData(): ?string
    {
        // dompdf embeds raw pixels, so a print-sized asset is used here
        // rather than the larger web logo.
        $path = collect([
            public_path('images/kcu-logo-print.png'),
            public_path('images/kcu-logo.png'),
        ])->first(fn (string $candidate) => is_file($candidate));

        if (! $path) {
            return null;
        }

        return 'data:image/png;base64,'.base64_encode((string) file_get_contents($path));
    }
}
