<?php

namespace Tests\Feature;

use App\Http\Middleware\EnsurePlatformSession;
use App\Models\Appointment;
use App\Models\Bill;
use App\Models\Branch;
use App\Models\Department;
use App\Models\Member;
use App\Models\Organization;
use App\Models\Patient;
use App\Models\User;
use App\Models\Visit;
use App\Services\Care\SpecialtyModuleService;
use App\Services\Care\SpecialtyShellService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class CareSpecialtyShellTest extends TestCase
{
    use RefreshDatabase;

    protected User $owner;

    protected Organization $organization;

    protected Branch $branch;

    protected function setUp(): void
    {
        parent::setUp();
        $this->withoutMiddleware(EnsurePlatformSession::class);

        $this->owner = User::create([
            'public_id' => 'shell-owner',
            'name' => 'Owner',
            'email' => 'shell@example.com',
        ]);

        $this->organization = Organization::create([
            'owner_ref' => $this->owner->public_id,
            'name' => 'Shell Clinic',
            'slug' => 'shell-clinic',
            'settings' => [
                'onboarded' => true,
                'facility_type' => 'clinic',
                'plan' => 'pro',
                'plan_expires_at' => now()->addMonth()->toIso8601String(),
                'queue_integration_enabled' => true,
            ],
        ]);

        Member::create([
            'owner_ref' => $this->owner->public_id,
            'organization_id' => $this->organization->id,
            'user_ref' => $this->owner->public_id,
            'role' => 'dentist',
        ]);

        $this->branch = Branch::create([
            'owner_ref' => $this->owner->public_id,
            'organization_id' => $this->organization->id,
            'name' => 'Main',
            'is_active' => true,
        ]);
    }

    public function test_activating_emergency_seeds_service_catalog_and_stage_map(): void
    {
        app(SpecialtyModuleService::class)->activate(
            $this->organization,
            $this->owner->public_id,
            'emergency',
        );

        $this->organization->refresh();
        $services = data_get($this->organization->settings, 'specialty_module_provisioning.emergency.services');
        $this->assertIsArray($services);
        $this->assertNotEmpty($services);
        $this->assertTrue(collect($services)->contains(fn ($s) => ($s['code'] ?? '') === 'er.consultation'));

        $shell = app(SpecialtyShellService::class);
        $stages = $shell->stages('emergency');
        $this->assertSame('arrival', $stages[0]['code'] ?? null);
        $this->assertGreaterThanOrEqual(4, count($stages));
        $this->assertSame('triage', $shell->workspaceTabForStage('emergency', 'arrival'));
        $this->assertSame('exam', $shell->workspaceTabForStage('ophthalmology', 'exam'));
        $this->assertSame('investigations', $shell->workspaceTabForStage('ophthalmology', 'investigation'));
        $this->assertSame('treat', $shell->workspaceTabForStage('ophthalmology', 'treatment'));
        $this->assertSame('assessment', $shell->workspaceTabForStage('physiotherapy', 'assessment'));
        $this->assertSame('session', $shell->workspaceTabForStage('physiotherapy', 'session'));
        $this->assertSame('exercises', $shell->workspaceTabForStage('physiotherapy', 'progress'));
        $this->assertSame('history', $shell->workspaceTabForStage('womens_health', 'history'));
        $this->assertSame('postnatal', $shell->workspaceTabForStage('womens_health', 'postnatal'));
        $this->assertSame('odontogram', $shell->workspaceTabForStage('dentistry', 'chair'));
        $this->assertSame('issue', $shell->workspaceTabForStage('blood_bank', 'issue'));
    }

    public function test_specialty_shell_overview_and_sections_render(): void
    {
        Member::query()->where('user_ref', $this->owner->public_id)->update(['role' => 'emergency_physician']);

        app(SpecialtyModuleService::class)->activate(
            $this->organization,
            $this->owner->public_id,
            'emergency',
        );

        $this->actingAs($this->owner)
            ->get(route('care.specialty.show', 'emergency'))
            ->assertOk()
            ->assertSee('Patient flow')
            ->assertSee('Waiting');

        $this->actingAs($this->owner)
            ->get(route('care.specialty.visits', 'emergency'))
            ->assertOk()
            ->assertSee('Patient flow');

        $this->actingAs($this->owner)
            ->get(route('care.specialty.history', 'emergency'))
            ->assertOk()
            ->assertSee('Visit history');

        $this->actingAs($this->owner)
            ->get(route('care.specialty.billing', 'emergency'))
            ->assertOk()
            ->assertSee('Service catalog')
            ->assertSee('er.consultation');

        $this->actingAs($this->owner)
            ->get(route('care.specialty.workspace', 'emergency'))
            ->assertRedirect(route('care.specialty.show', 'emergency'));
    }

    public function test_dentistry_shell_has_chair_stage_and_catalog(): void
    {
        app(SpecialtyModuleService::class)->activate(
            $this->organization,
            $this->owner->public_id,
            'dentistry',
        );

        $shell = app(SpecialtyShellService::class);
        $codes = collect($shell->stages('dentistry'))->pluck('code')->all();
        $this->assertContains('chair', $codes);
        $this->assertContains('procedure', $codes);

        $this->actingAs($this->owner)
            ->get(route('care.specialty.billing', 'dentistry'))
            ->assertOk()
            ->assertSee('den.fill');
    }

    public function test_workspace_can_add_catalog_service_to_visit_bill(): void
    {
        Member::query()->where('user_ref', $this->owner->public_id)->update(['role' => 'emergency_physician']);

        app(SpecialtyModuleService::class)->activate(
            $this->organization,
            $this->owner->public_id,
            'emergency',
        );

        $department = Department::query()
            ->where('branch_id', $this->branch->id)
            ->where('type', 'emergency')
            ->firstOrFail();

        $patient = Patient::create([
            'owner_ref' => $this->owner->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $this->branch->id,
            'patient_number' => 'P-ER-1',
            'first_name' => 'Ama',
            'last_name' => 'Mensah',
            'gender' => 'female',
            'date_of_birth' => '1992-01-01',
        ]);

        $visit = Visit::create([
            'owner_ref' => $this->owner->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $this->branch->id,
            'patient_id' => $patient->id,
            'status' => Visit::STATUS_OPEN,
            'checked_in_at' => now(),
        ]);

        Appointment::create([
            'owner_ref' => $this->owner->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $this->branch->id,
            'patient_id' => $patient->id,
            'department_id' => $department->id,
            'visit_id' => $visit->id,
            'type' => Appointment::TYPE_WALK_IN,
            'status' => Appointment::STATUS_WAITING,
            'scheduled_at' => now(),
            'waiting_at' => now(),
        ]);

        $this->actingAs($this->owner)
            ->post(route('care.specialty.services.add', ['module' => 'emergency', 'visit' => $visit]), [
                'service_code' => 'er.consultation',
            ])
            ->assertRedirect();

        $this->assertDatabaseHas('care_bills', [
            'visit_id' => $visit->id,
            'patient_id' => $patient->id,
        ]);

        $bill = Bill::query()->where('visit_id', $visit->id)->first();
        $this->assertNotNull($bill);
        $this->assertTrue(
            $bill->lineItems()->where('description', 'Emergency consultation')->exists()
        );
    }

    public function test_specialty_start_consultation_opens_specialty_workspace(): void
    {
        app(SpecialtyModuleService::class)->activate(
            $this->organization,
            $this->owner->public_id,
            'dentistry',
        );

        $department = Department::query()
            ->where('branch_id', $this->branch->id)
            ->where('type', 'dental')
            ->firstOrFail();

        $patient = Patient::create([
            'owner_ref' => $this->owner->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $this->branch->id,
            'patient_number' => 'P-DEN-1',
            'first_name' => 'Abena',
            'last_name' => 'Osei',
            'gender' => 'female',
            'date_of_birth' => '1993-01-01',
        ]);

        $visit = Visit::create([
            'owner_ref' => $this->owner->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $this->branch->id,
            'patient_id' => $patient->id,
            'status' => Visit::STATUS_OPEN,
            'checked_in_at' => now(),
        ]);

        $appointment = Appointment::create([
            'owner_ref' => $this->owner->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $this->branch->id,
            'patient_id' => $patient->id,
            'department_id' => $department->id,
            'visit_id' => $visit->id,
            'type' => Appointment::TYPE_WALK_IN,
            'status' => Appointment::STATUS_WAITING,
            'scheduled_at' => now(),
            'waiting_at' => now(),
            'checked_in_at' => now(),
        ]);

        $doctorUser = User::create([
            'public_id' => 'shell-dental-doc',
            'name' => 'Dental Doctor',
            'email' => 'shell-dental@example.com',
        ]);
        $doctorMember = Member::create([
            'owner_ref' => $this->owner->public_id,
            'organization_id' => $this->organization->id,
            'user_ref' => $doctorUser->public_id,
            'role' => 'doctor',
            'branch_id' => $this->branch->id,
        ]);
        \App\Models\Practitioner::create([
            'owner_ref' => $this->owner->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $this->branch->id,
            'department_id' => $department->id,
            'member_id' => $doctorMember->id,
            'user_ref' => $doctorUser->public_id,
            'name' => 'Dental Doctor',
            'specialty' => 'Dentistry',
            'is_active' => true,
        ]);

        $response = $this->actingAs($doctorUser)
            ->post(route('care.specialty.consultation.start', [
                'module' => 'dentistry',
                'visit' => $visit,
            ]));

        $consultation = \App\Models\Consultation::query()
            ->where('appointment_id', $appointment->id)
            ->first();
        $this->assertNotNull($consultation);

        $response->assertRedirect(route('care.specialty.workspace', [
            'module' => 'dentistry',
            'visit' => $visit,
            'tab' => 'odontogram',
        ]));
        $this->assertSame(Appointment::STATUS_IN_CONSULTATION, $appointment->fresh()->status);
    }

    public function test_workspace_includes_timeline_tab_and_complete_action(): void
    {
        Member::query()->where('user_ref', $this->owner->public_id)->update(['role' => 'dentist']);

        app(SpecialtyModuleService::class)->activate(
            $this->organization,
            $this->owner->public_id,
            'dentistry',
        );

        $department = Department::query()
            ->where('branch_id', $this->branch->id)
            ->where('type', 'dental')
            ->firstOrFail();

        $patient = Patient::create([
            'owner_ref' => $this->owner->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $this->branch->id,
            'patient_number' => 'P-DEN-TL',
            'first_name' => 'Afia',
            'last_name' => 'Darko',
            'gender' => 'female',
            'date_of_birth' => '1992-01-01',
        ]);

        $visit = Visit::create([
            'owner_ref' => $this->owner->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $this->branch->id,
            'patient_id' => $patient->id,
            'status' => Visit::STATUS_IN_PROGRESS,
            'checked_in_at' => now(),
        ]);

        $appointment = Appointment::create([
            'owner_ref' => $this->owner->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $this->branch->id,
            'patient_id' => $patient->id,
            'department_id' => $department->id,
            'visit_id' => $visit->id,
            'type' => Appointment::TYPE_WALK_IN,
            'status' => Appointment::STATUS_IN_CONSULTATION,
            'scheduled_at' => now(),
            'waiting_at' => now(),
            'checked_in_at' => now(),
            'started_at' => now(),
            'queue_ticket_status' => 'serving',
        ]);

        \App\Models\Consultation::create([
            'owner_ref' => $this->owner->public_id,
            'visit_id' => $visit->id,
            'appointment_id' => $appointment->id,
            'patient_id' => $patient->id,
            'status' => \App\Models\Consultation::STATUS_DRAFT,
            'started_at' => now(),
        ]);

        $tabs = app(SpecialtyShellService::class)->workspaceTabs('dentistry');
        $this->assertArrayHasKey('timeline', $tabs);
        $this->assertSame(['overview', 'timeline'], array_slice(array_keys($tabs), 0, 2));

        $this->actingAs($this->owner)
            ->get(route('care.specialty.workspace', [
                'module' => 'dentistry',
                'visit' => $visit,
                'tab' => 'timeline',
            ]))
            ->assertOk()
            ->assertSee('Timeline')
            ->assertSee('Patient timeline')
            ->assertSee('Complete consultation')
            ->assertDontSee('>Call again<', false);

        $this->actingAs($this->owner)
            ->get(route('care.specialty.workspace', [
                'module' => 'dentistry',
                'visit' => $visit,
                'tab' => 'overview',
            ]))
            ->assertOk()
            ->assertDontSee('Patient timeline');
    }

    public function test_called_workspace_shows_call_again_until_session_starts(): void
    {
        Member::query()->where('user_ref', $this->owner->public_id)->update(['role' => 'dentist']);

        app(SpecialtyModuleService::class)->activate(
            $this->organization,
            $this->owner->public_id,
            'dentistry',
        );

        $department = Department::query()
            ->where('branch_id', $this->branch->id)
            ->where('type', 'dental')
            ->firstOrFail();

        $patient = Patient::create([
            'owner_ref' => $this->owner->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $this->branch->id,
            'patient_number' => 'P-DEN-CALL',
            'first_name' => 'Kofi',
            'last_name' => 'Mensah',
            'gender' => 'male',
            'date_of_birth' => '1988-01-01',
        ]);

        $visit = Visit::create([
            'owner_ref' => $this->owner->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $this->branch->id,
            'patient_id' => $patient->id,
            'status' => Visit::STATUS_OPEN,
            'checked_in_at' => now(),
        ]);

        Appointment::create([
            'owner_ref' => $this->owner->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $this->branch->id,
            'patient_id' => $patient->id,
            'department_id' => $department->id,
            'visit_id' => $visit->id,
            'type' => Appointment::TYPE_WALK_IN,
            'status' => Appointment::STATUS_WAITING,
            'scheduled_at' => now(),
            'waiting_at' => now(),
            'checked_in_at' => now(),
            'queue_ticket_status' => 'called',
            'queue_ticket_number' => 'DEN001',
        ]);

        $this->actingAs($this->owner)
            ->get(route('care.specialty.workspace', [
                'module' => 'dentistry',
                'visit' => $visit,
            ]))
            ->assertOk()
            ->assertSee('Call again')
            ->assertSee('Start')
            ->assertDontSee('Complete consultation');
    }
}
