<?php

namespace App\Livewire\Portal;

use App\Domain\Document\Enums\DocumentStatus;
use App\Domain\Document\Enums\DocumentType;
use App\Domain\Document\Models\Document;
use App\Domain\Participant\Models\Participant;
use App\Livewire\Portal\Concerns\PortalScreen;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use App\Domain\Shared\Traits\ChecksTemporaryUploads;
use Livewire\Component;
use Livewire\WithFileUploads;

/**
 * Uploading and renewing the member's own documents.
 *
 * The admin half of this has been complete for a long time —
 * `DocumentApprovalList`, a nightly `documents:expire`, a
 * `MedicalCertificateAlert`. The member half did not exist at all, and the
 * deleted API's DocumentController was index-only. So a medical certificate
 * expired at 06:00 on a Tuesday and the member had no way, inside the product,
 * to do anything about it before a coach turned them away at the gate.
 */
#[Layout('layouts.portal')]
#[Title('المستندات')]
class PortalDocuments extends Component
{
    use PortalScreen, WithFileUploads, ChecksTemporaryUploads;

    public string $documentType = 'medical_certificate';

    public string $expiresAt = '';

    public $file;

    public function mount(): void
    {
        $this->authorizePortal('portal.documents');
    }

    protected function rules(): array
    {
        return [
            'documentType' => ['required', 'in:' . implode(',', array_column(DocumentType::cases(), 'value'))],
            // A medical certificate without an expiry is a certificate nobody
            // can act on: the nightly job has nothing to compare against.
            'expiresAt' => ['nullable', 'date', 'after:today'],
            'file' => ['required', 'file', 'max:' . config('uploads.max_kb'), 'mimes:png,jpg,jpeg,webp,pdf'],
        ];
    }

    protected function messages(): array
    {
        return [
            'file.required' => __('اختر الملف أولاً'),
            'file.mimes' => __('الملف يجب أن يكون صورة أو PDF'),
            'file.max' => __('حجم الملف يتجاوز :mb ميجابايت', ['mb' => intdiv((int) config('uploads.max_kb'), 1024)]),
            'expiresAt.after' => __('تاريخ الانتهاء يجب أن يكون في المستقبل'),
        ];
    }

    public function upload(): void
    {
        if (! $this->temporaryUploadIsUsable('file', $this->file)) {
            return;
        }

        $this->validate();

        $participantId = $this->activeParticipantId();

        // The private `local` disk, and a streaming controller to read it back.
        // The deleted API returned asset('storage/'.$path) for documents stored
        // on the private disk — a URL that either 404s or, if anyone had
        // "fixed" it by moving the files, would serve national IDs and medical
        // records to whoever guessed the path.
        $path = $this->file->store(
            'documents/' . app('current_academy')->id . '/' . $participantId,
            'local'
        );

        Document::create([
            'academy_id' => app('current_academy')->id,
            'documentable_type' => Participant::class,
            'documentable_id' => $participantId,
            'document_type' => $this->documentType,
            'file_path' => $path,
            'original_filename' => $this->file->getClientOriginalName(),
            'mime_type' => $this->file->getMimeType(),
            'file_size' => $this->file->getSize(),
            // Uploaded, not approved. A member cannot approve their own
            // medical certificate any more than they can approve their own
            // payment.
            'status' => DocumentStatus::Pending,
            'expires_at' => $this->expiresAt ?: null,
            'uploaded_by' => auth()->id(),
            'created_by' => auth()->id(),
        ]);

        $this->reset(['file', 'expiresAt']);

        session()->flash('success', __('تم رفع المستند — سيراجعه فريق الأكاديمية'));
    }

    public function render()
    {
        $familyIds = $this->familyParticipantIds();

        return view('livewire.portal.portal-documents', [
            'documents' => Document::where('documentable_type', Participant::class)
                ->whereIn('documentable_id', $familyIds)
                ->with('documentable.person')
                ->orderByDesc('created_at')
                ->get(),
            'types' => DocumentType::cases(),
            'activeName' => $this->portal()->activeParticipant()?->person?->name_ar,
        ]);
    }
}
