<?php

namespace App\Domain\Clinical;

use App\Enums\ToothState;
use App\Models\Patient;
use App\Models\ToothRecord;
use Illuminate\Support\Collection;

/**
 * The chart is reconstructed from dated tooth_records — never a static grid —
 * so every tooth has a complete, auditable timeline.
 */
class ToothChartService
{
    /**
     * Current chart: one entry per FDI tooth with the latest condition,
     * planned markers, and full history.
     */
    public function chartFor(Patient $patient): Collection
    {
        $records = ToothRecord::query()
            ->where('patient_id', $patient->id)
            ->with('recorder:id,name')
            ->orderByDesc('recorded_at')
            ->orderByDesc('id')
            ->get()
            ->groupBy('tooth');

        return collect(Fdi::all())->mapWithKeys(function (int $tooth) use ($records) {
            /** @var Collection<int, ToothRecord> $history */
            $history = $records->get($tooth, collect());

            // The tooth's display condition = most recent non-planned record.
            $current = $history->first(fn ($r) => $r->state !== ToothState::Planned);

            return [$tooth => [
                'tooth' => $tooth,
                'condition' => $current?->condition,
                'color' => $current?->conditionColor(),
                'state' => $current?->state?->value,
                'has_planned' => $history->contains(fn ($r) => $r->state === ToothState::Planned),
                'records' => $history->map(fn (ToothRecord $r) => $this->present($r))->values(),
            ]];
        });
    }

    public function record(
        Patient $patient,
        int $tooth,
        string $condition,
        ToothState $state = ToothState::Existing,
        ?array $surfaces = null,
        ?string $note = null,
        ?int $planItemId = null,
        ?int $recordedBy = null,
    ): ToothRecord {
        abort_unless(Fdi::isValid($tooth), 422, __('Invalid FDI tooth number.'));
        abort_unless(
            array_key_exists($condition, config('dental.conditions')),
            422,
            __('Unknown condition.')
        );

        $surfaces = $surfaces
            ? array_values(array_intersect(config('dental.surfaces'), array_map('strtoupper', $surfaces)))
            : null;

        return ToothRecord::create([
            'patient_id' => $patient->id,
            'tooth' => $tooth,
            'surfaces' => $surfaces ?: null,
            'condition' => $condition,
            'state' => $state,
            'note' => $note,
            'treatment_plan_item_id' => $planItemId,
            'recorded_by' => $recordedBy,
            'recorded_at' => now(),
        ]);
    }

    public function present(ToothRecord $r): array
    {
        return [
            'id' => $r->id,
            'condition' => $r->condition,
            'condition_label' => $r->conditionLabel(),
            'color' => $r->conditionColor(),
            'state' => $r->state->value,
            'state_label' => $r->state->label(),
            'surfaces' => $r->surfaces,
            'note' => $r->note,
            'recorded_by' => $r->recorder?->name,
            'recorded_at' => $r->recorded_at->toIso8601String(),
            'recorded_at_human' => $r->recorded_at->diffForHumans(),
            'from_plan' => $r->treatment_plan_item_id !== null,
        ];
    }
}
