<?php

namespace Tests\Feature;

use App\Domain\Clinical\ToothChartService;
use App\Domain\Clinical\TreatmentPlanService;
use App\Enums\PlanItemStatus;
use App\Enums\ToothState;
use App\Enums\TreatmentPlanStatus;
use App\Models\Procedure;
use App\Models\Tenant;
use App\Models\ToothRecord;
use App\Models\TreatmentPlan;
use App\Support\Tenancy;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class TreatmentPlanTest extends TestCase
{
    use RefreshDatabase;

    protected Tenant $tenant;
    protected TreatmentPlan $plan;
    protected Procedure $procedure;

    protected function setUp(): void
    {
        parent::setUp();
        $this->seed();

        $this->tenant = Tenant::create(['name' => 'Smile', 'slug' => 'smile']);
        app(Tenancy::class)->set($this->tenant);

        $this->procedure = Procedure::factory()->create(); // filling, 35,000
        $this->plan = TreatmentPlan::factory()->create();
    }

    protected function service(): TreatmentPlanService
    {
        return app(TreatmentPlanService::class);
    }

    public function test_adding_a_tooth_item_marks_the_tooth_planned(): void
    {
        $this->service()->addItem($this->plan, [
            'procedure_id' => $this->procedure->id, 'tooth' => 16, 'surfaces' => ['O'],
        ]);

        $chart = app(ToothChartService::class)->chartFor($this->plan->patient);
        $this->assertTrue($chart[16]['has_planned']);

        $record = ToothRecord::where('tooth', 16)->firstOrFail();
        $this->assertSame(ToothState::Planned, $record->state);
        $this->assertNotNull($record->treatment_plan_item_id);
    }

    public function test_totals_and_discount(): void
    {
        $svc = $this->service();
        $svc->addItem($this->plan, ['procedure_id' => $this->procedure->id, 'tooth' => 16]);
        $svc->addItem($this->plan, ['procedure_id' => $this->procedure->id, 'tooth' => 26, 'price' => 40000]);

        $this->plan->update(['discount_amount' => 5000]);
        $plan = $this->plan->fresh('items');

        $this->assertSame(75000, $plan->totalGross());
        $this->assertSame(70000, $plan->totalNet());
    }

    public function test_cancelled_items_are_excluded_from_totals(): void
    {
        $svc = $this->service();
        $a = $svc->addItem($this->plan, ['procedure_id' => $this->procedure->id, 'tooth' => 16]);
        $svc->addItem($this->plan, ['procedure_id' => $this->procedure->id, 'tooth' => 26]);

        $svc->cancelItem($a);

        $this->assertSame(35000, $this->plan->fresh('items')->totalGross());
    }

    public function test_completing_an_item_writes_completed_chart_record(): void
    {
        $item = $this->service()->addItem($this->plan, [
            'procedure_id' => $this->procedure->id, 'tooth' => 16, 'surfaces' => ['M', 'O'],
        ]);

        $this->service()->completeItem($item);

        $completed = ToothRecord::where('tooth', 16)
            ->where('state', ToothState::Completed->value)->first();

        $this->assertNotNull($completed);
        $this->assertSame('filling', $completed->condition);
        $this->assertSame(['M', 'O'], $completed->surfaces);

        $chart = app(ToothChartService::class)->chartFor($this->plan->patient);
        $this->assertSame('filling', $chart[16]['condition']);
    }

    public function test_plan_rolls_forward_and_completes_automatically(): void
    {
        $svc = $this->service();
        $a = $svc->addItem($this->plan, ['procedure_id' => $this->procedure->id, 'tooth' => 16]);
        $b = $svc->addItem($this->plan, ['procedure_id' => $this->procedure->id, 'tooth' => 26]);

        $svc->completeItem($a);
        $this->assertSame(TreatmentPlanStatus::InProgress, $this->plan->fresh()->status);

        $svc->completeItem($b);
        $plan = $this->plan->fresh();
        $this->assertSame(TreatmentPlanStatus::Completed, $plan->status);
        $this->assertNotNull($plan->completed_at);
    }

    public function test_completed_items_cannot_be_completed_twice(): void
    {
        $item = $this->service()->addItem($this->plan, ['procedure_id' => $this->procedure->id, 'tooth' => 16]);
        $this->service()->completeItem($item);

        $this->expectException(\Symfony\Component\HttpKernel\Exception\HttpException::class);
        $this->service()->completeItem($item->fresh());
    }

    public function test_invalid_plan_status_transition_rejected(): void
    {
        $this->expectException(\Symfony\Component\HttpKernel\Exception\HttpException::class);
        // accepted → completed directly is not allowed (must pass in_progress)
        $this->service()->changeStatus($this->plan, TreatmentPlanStatus::Completed);
    }

    public function test_item_completion_status_is_idempotent_on_plan(): void
    {
        $svc = $this->service();
        $item = $svc->addItem($this->plan, ['procedure_id' => $this->procedure->id, 'tooth' => 16]);
        $svc->completeItem($item);

        $this->assertSame(PlanItemStatus::Completed, $item->fresh()->status);
        $this->assertSame(TreatmentPlanStatus::Completed, $this->plan->fresh()->status);
    }
}
