<?php

namespace App\Services\Care\Dentistry;

use App\Models\DentalPerioExam;
use App\Models\DentalPerioSite;
use App\Models\Organization;
use App\Models\Patient;
use App\Models\Visit;
use App\Services\Care\AuditLogger;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class DentalPerioService
{
    /**
     * @return Collection<int, DentalPerioExam>
     */
    public function examsForPatient(Organization $organization, Patient $patient, string $ownerRef, int $limit = 10): Collection
    {
        return DentalPerioExam::owned($ownerRef)
            ->where('organization_id', $organization->id)
            ->where('patient_id', $patient->id)
            ->with('sites')
            ->latest('id')
            ->limit($limit)
            ->get();
    }

    public function latestForPatient(Organization $organization, Patient $patient, string $ownerRef): ?DentalPerioExam
    {
        return $this->examsForPatient($organization, $patient, $ownerRef, 1)->first();
    }

    /**
     * @param  list<array{tooth_code: string, surface: string, probing_mm?: ?int, bleeding?: bool, plaque?: bool, recession_mm?: ?int}>  $sites
     */
    public function saveExam(
        Organization $organization,
        Patient $patient,
        string $ownerRef,
        array $sites,
        ?Visit $visit = null,
        ?string $notes = null,
        ?string $actorRef = null,
    ): DentalPerioExam {
        return DB::transaction(function () use ($organization, $patient, $ownerRef, $sites, $visit, $notes, $actorRef) {
            $exam = DentalPerioExam::create([
                'owner_ref' => $ownerRef,
                'organization_id' => $organization->id,
                'patient_id' => $patient->id,
                'visit_id' => $visit?->id,
                'exam_date' => now()->toDateString(),
                'examiner' => $actorRef ?? $ownerRef,
                'notes' => $notes,
            ]);

            foreach ($sites as $row) {
                $tooth = (string) ($row['tooth_code'] ?? '');
                $surface = strtoupper((string) ($row['surface'] ?? ''));
                if (! DentalCatalog::isValidToothCode($tooth) || ! in_array($surface, DentalCatalog::perioSurfaces(), true)) {
                    continue;
                }
                if (($row['probing_mm'] ?? null) === null
                    && empty($row['bleeding'])
                    && empty($row['plaque'])
                    && ($row['recession_mm'] ?? null) === null) {
                    continue;
                }

                DentalPerioSite::create([
                    'perio_exam_id' => $exam->id,
                    'tooth_code' => $tooth,
                    'surface' => $surface,
                    'probing_mm' => isset($row['probing_mm']) ? (int) $row['probing_mm'] : null,
                    'bleeding' => (bool) ($row['bleeding'] ?? false),
                    'plaque' => (bool) ($row['plaque'] ?? false),
                    'recession_mm' => isset($row['recession_mm']) ? (int) $row['recession_mm'] : null,
                ]);
            }

            AuditLogger::record(
                $ownerRef,
                'dental.perio.saved',
                $organization->id,
                $actorRef,
                DentalPerioExam::class,
                $exam->id,
            );

            return $exam->fresh('sites');
        });
    }
}
