<?php

namespace App\Services\Care\Dentistry;

use App\Models\DentalLabCase;
use App\Models\Organization;
use App\Models\Patient;
use App\Models\Visit;
use App\Services\Care\AuditLogger;
use Illuminate\Support\Collection;

class DentalLabCaseService
{
    /**
     * @return Collection<int, DentalLabCase>
     */
    public function casesForPatient(Organization $organization, Patient $patient, string $ownerRef, int $limit = 30): Collection
    {
        return DentalLabCase::owned($ownerRef)
            ->where('organization_id', $organization->id)
            ->where('patient_id', $patient->id)
            ->latest('id')
            ->limit($limit)
            ->get();
    }

    /**
     * @param  array{case_type: string, lab_name?: ?string, tooth_codes?: list<string>, plan_item_id?: ?int, due_at?: ?string, notes?: ?string, status?: string}  $data
     */
    public function create(
        Organization $organization,
        Patient $patient,
        string $ownerRef,
        array $data,
        ?Visit $visit = null,
        ?string $actorRef = null,
    ): DentalLabCase {
        $type = (string) ($data['case_type'] ?? '');
        if (! array_key_exists($type, DentalCatalog::labCaseTypes())) {
            throw new \InvalidArgumentException("Invalid lab case type [{$type}].");
        }

        $status = (string) ($data['status'] ?? DentalLabCase::STATUS_DRAFT);
        if (! array_key_exists($status, DentalCatalog::labCaseStatuses())) {
            throw new \InvalidArgumentException("Invalid lab case status [{$status}].");
        }

        $toothCodes = array_values(array_filter(
            $data['tooth_codes'] ?? [],
            fn ($c) => DentalCatalog::isValidToothCode((string) $c),
        ));

        $case = DentalLabCase::create([
            'owner_ref' => $ownerRef,
            'organization_id' => $organization->id,
            'patient_id' => $patient->id,
            'visit_id' => $visit?->id,
            'plan_item_id' => $data['plan_item_id'] ?? null,
            'tooth_codes' => $toothCodes,
            'case_type' => $type,
            'lab_name' => $data['lab_name'] ?? null,
            'status' => $status,
            'ordered_at' => in_array($status, [DentalLabCase::STATUS_ORDERED, DentalLabCase::STATUS_SENT], true) ? now() : null,
            'due_at' => $data['due_at'] ?? null,
            'notes' => $data['notes'] ?? null,
            'created_by' => $actorRef ?? $ownerRef,
        ]);

        AuditLogger::record($ownerRef, 'dental.lab.created', $organization->id, $actorRef, DentalLabCase::class, $case->id);

        return $case;
    }

    public function transition(
        DentalLabCase $case,
        string $status,
        string $ownerRef,
        ?string $actorRef = null,
    ): DentalLabCase {
        if (! array_key_exists($status, DentalCatalog::labCaseStatuses())) {
            throw new \InvalidArgumentException("Invalid lab case status [{$status}].");
        }

        $updates = ['status' => $status];
        if (in_array($status, [DentalLabCase::STATUS_ORDERED, DentalLabCase::STATUS_SENT], true) && ! $case->ordered_at) {
            $updates['ordered_at'] = now();
        }
        if (in_array($status, [DentalLabCase::STATUS_RECEIVED, DentalLabCase::STATUS_FITTED], true) && ! $case->received_at) {
            $updates['received_at'] = now();
        }

        $case->update($updates);

        AuditLogger::record($ownerRef, 'dental.lab.transitioned', $case->organization_id, $actorRef, DentalLabCase::class, $case->id, [
            'status' => $status,
        ]);

        return $case->fresh();
    }
}
