<?php

namespace App\Domain\Clinical;

use App\Enums\PlanItemStatus;
use App\Enums\ToothState;
use App\Enums\TreatmentPlanStatus;
use App\Models\Procedure;
use App\Models\TreatmentPlan;
use App\Models\TreatmentPlanItem;
use Illuminate\Support\Facades\DB;

class TreatmentPlanService
{
    public function __construct(protected ToothChartService $chart)
    {
    }

    public function addItem(TreatmentPlan $plan, array $data, ?int $userId = null): TreatmentPlanItem
    {
        abort_if(in_array($plan->status, [TreatmentPlanStatus::Completed, TreatmentPlanStatus::Cancelled], true),
            422, __('This plan can no longer be edited.'));

        $procedure = Procedure::findOrFail($data['procedure_id']);

        return DB::transaction(function () use ($plan, $procedure, $data, $userId) {
            $item = $plan->items()->create([
                'procedure_id' => $procedure->id,
                'tooth' => $data['tooth'] ?? null,
                'surfaces' => $data['surfaces'] ?? null,
                'price' => $data['price'] ?? $procedure->default_price,
                'note' => $data['note'] ?? null,
            ]);

            // Tooth-linked items mark the tooth as PLANNED on the chart.
            if ($item->tooth && $procedure->default_condition) {
                $this->chart->record(
                    patient: $plan->patient,
                    tooth: $item->tooth,
                    condition: $procedure->default_condition,
                    state: ToothState::Planned,
                    surfaces: $item->surfaces,
                    note: __('Planned: :procedure', ['procedure' => $procedure->name()]),
                    planItemId: $item->id,
                    recordedBy: $userId,
                );
            }

            return $item;
        });
    }

    /**
     * Completing an item writes the COMPLETED chart record automatically
     * and rolls the plan forward (accepted → in_progress → completed).
     */
    public function completeItem(TreatmentPlanItem $item, ?int $userId = null, ?int $appointmentId = null): TreatmentPlanItem
    {
        abort_if($item->status === PlanItemStatus::Completed, 422, __('Item is already completed.'));
        abort_if($item->status === PlanItemStatus::Cancelled, 422, __('Cancelled items cannot be completed.'));

        return DB::transaction(function () use ($item, $userId, $appointmentId) {
            $item->update([
                'status' => PlanItemStatus::Completed,
                'completed_at' => now(),
                'appointment_id' => $appointmentId ?? $item->appointment_id,
            ]);

            $procedure = $item->procedure;
            if ($item->tooth && $procedure?->default_condition) {
                $this->chart->record(
                    patient: $item->plan->patient,
                    tooth: $item->tooth,
                    condition: $procedure->default_condition,
                    state: ToothState::Completed,
                    surfaces: $item->surfaces,
                    note: __('Completed: :procedure', ['procedure' => $procedure->name()]),
                    planItemId: $item->id,
                    recordedBy: $userId,
                );
            }

            $this->syncPlanStatus($item->plan->fresh('items'));

            return $item->fresh();
        });
    }

    public function cancelItem(TreatmentPlanItem $item): TreatmentPlanItem
    {
        abort_if($item->status === PlanItemStatus::Completed, 422, __('Completed items cannot be cancelled.'));
        $item->update(['status' => PlanItemStatus::Cancelled]);
        $this->syncPlanStatus($item->plan->fresh('items'));

        return $item->fresh();
    }

    public function changeStatus(TreatmentPlan $plan, TreatmentPlanStatus $to): TreatmentPlan
    {
        abort_unless($plan->status->canTransitionTo($to), 422,
            __('Cannot change status from :from to :to.', [
                'from' => $plan->status->label(), 'to' => $to->label(),
            ]));

        $plan->update([
            'status' => $to,
            'completed_at' => $to === TreatmentPlanStatus::Completed ? now() : $plan->completed_at,
        ]);

        return $plan;
    }

    protected function syncPlanStatus(TreatmentPlan $plan): void
    {
        $billable = $plan->items->reject(fn ($i) => $i->status === PlanItemStatus::Cancelled);
        $done = $billable->where('status', PlanItemStatus::Completed);

        if ($billable->isNotEmpty() && $done->count() === $billable->count()) {
            if ($plan->status !== TreatmentPlanStatus::Completed) {
                $plan->update(['status' => TreatmentPlanStatus::Completed, 'completed_at' => now()]);
            }

            return;
        }

        if ($done->isNotEmpty()
            && in_array($plan->status, [TreatmentPlanStatus::Accepted, TreatmentPlanStatus::Proposed], true)) {
            $plan->update(['status' => TreatmentPlanStatus::InProgress]);
        }
    }
}
