<?php

namespace Tests\Feature;

use App\Http\Middleware\EnsurePlatformSession;
use App\Models\Assessment;
use App\Models\AssessmentQuestion;
use App\Models\AssessmentTemplate;
use App\Models\Branch;
use App\Models\Consultation;
use App\Models\Member;
use App\Models\Organization;
use App\Models\Patient;
use App\Models\Practitioner;
use App\Models\User;
use App\Models\Visit;
use App\Services\Care\CareFeatures;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Str;
use Tests\TestCase;

class CareAssessmentCaptureTest extends TestCase
{
    use RefreshDatabase;

    protected User $user;

    protected Organization $organization;

    protected Branch $branch;

    protected Patient $patient;

    protected Member $member;

    protected AssessmentTemplate $universal;

    protected AssessmentTemplate $nihss;

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

        $this->user = User::create([
            'public_id' => 'assess-capture-user',
            'name' => 'Capture User',
            'email' => 'capture@example.com',
        ]);

        $this->organization = Organization::create([
            'owner_ref' => $this->user->public_id,
            'name' => 'Capture Clinic',
            'slug' => 'capture-clinic',
            'timezone' => 'UTC',
            'settings' => [
                'onboarded' => true,
                'rollout' => [
                    CareFeatures::ASSESSMENTS_ENGINE => true,
                ],
            ],
        ]);

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

        $this->member = Member::create([
            'owner_ref' => $this->user->public_id,
            'organization_id' => $this->organization->id,
            'user_ref' => $this->user->public_id,
            'role' => 'doctor',
            'branch_id' => $this->branch->id,
        ]);

        // Doctors are branch-scoped via linked practitioner desks.
        Practitioner::create([
            'owner_ref' => $this->user->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $this->branch->id,
            'member_id' => $this->member->id,
            'user_ref' => $this->user->public_id,
            'name' => 'Dr Capture',
            'specialty' => 'General Practice',
            'is_active' => true,
        ]);

        $this->patient = Patient::create([
            'uuid' => (string) Str::uuid(),
            'owner_ref' => $this->user->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => $this->branch->id,
            'patient_number' => 'LC-CAP-001',
            'first_name' => 'Ama',
            'last_name' => 'Mensah',
        ]);

        $this->universal = AssessmentTemplate::create([
            'code' => 'universal_intake',
            'name' => 'Universal Intake',
            'category' => AssessmentTemplate::CATEGORY_UNIVERSAL,
            'version' => 1,
            'is_current' => true,
            'is_active' => true,
            'meta' => ['capture_roles' => ['doctor', 'nurse']],
        ]);

        AssessmentQuestion::create([
            'template_id' => $this->universal->id,
            'code' => 'chief_complaint',
            'label' => 'Chief complaint',
            'answer_type' => AssessmentQuestion::TYPE_TEXT,
            'is_required' => true,
            'sort_order' => 1,
        ]);

        AssessmentQuestion::create([
            'template_id' => $this->universal->id,
            'code' => 'pain_score',
            'label' => 'Pain score',
            'answer_type' => AssessmentQuestion::TYPE_SCALE,
            'options' => ['min' => 0, 'max' => 10],
            'is_required' => false,
            'sort_order' => 2,
        ]);

        $this->nihss = AssessmentTemplate::create([
            'code' => 'nihss',
            'name' => 'NIH Stroke Scale',
            'category' => AssessmentTemplate::CATEGORY_DISEASE,
            'version' => 1,
            'is_current' => true,
            'is_active' => true,
            'scoring_strategy' => 'sum_items',
            'meta' => ['capture_roles' => ['doctor']],
        ]);

        AssessmentQuestion::create([
            'template_id' => $this->nihss->id,
            'code' => 'loc',
            'label' => 'Level of consciousness',
            'answer_type' => AssessmentQuestion::TYPE_SCORE_ITEM,
            'options' => [
                'choices' => [
                    ['code' => '0', 'label' => 'Alert', 'score' => 0],
                    ['code' => '1', 'label' => 'Not alert', 'score' => 1],
                    ['code' => '2', 'label' => 'Obtunded', 'score' => 2],
                ],
            ],
            'is_required' => true,
            'sort_order' => 1,
        ]);
    }

    protected function setMemberRole(string $role): void
    {
        $this->member->update(['role' => $role]);
    }

    public function test_routes_404_when_feature_flag_disabled(): void
    {
        $this->organization->update([
            'settings' => ['onboarded' => true, 'rollout' => [CareFeatures::ASSESSMENTS_ENGINE => false]],
        ]);

        $this->actingAs($this->user)
            ->get(route('care.assessments.index', $this->patient))
            ->assertNotFound();
    }

    public function test_doctor_can_start_nihss(): void
    {
        $this->setMemberRole('doctor');

        $this->actingAs($this->user)
            ->post(route('care.assessments.store', $this->patient), [
                'template_code' => 'nihss',
            ])
            ->assertRedirect();

        $assessment = Assessment::first();
        $this->assertNotNull($assessment);
        $this->assertSame(Assessment::STATUS_DRAFT, $assessment->status);
        $this->assertSame($this->nihss->id, $assessment->template_id);
        $this->assertDatabaseHas('care_audit_logs', ['action' => 'assessment.started']);
    }

    public function test_nurse_can_start_universal_but_not_nihss(): void
    {
        $this->setMemberRole('nurse');

        $this->actingAs($this->user)
            ->post(route('care.assessments.store', $this->patient), [
                'template_code' => 'universal_intake',
            ])
            ->assertRedirect();

        $this->assertSame(1, Assessment::count());

        $this->actingAs($this->user)
            ->post(route('care.assessments.store', $this->patient), [
                'template_code' => 'nihss',
            ])
            ->assertForbidden();
    }

    public function test_hospital_admin_can_start_nihss(): void
    {
        $this->setMemberRole('hospital_admin');

        $this->actingAs($this->user)
            ->post(route('care.assessments.store', $this->patient), [
                'template_code' => 'nihss',
            ])
            ->assertRedirect();

        $this->assertSame(1, Assessment::where('template_id', $this->nihss->id)->count());
    }

    public function test_super_admin_can_start_nihss(): void
    {
        $this->setMemberRole('super_admin');

        $this->actingAs($this->user)
            ->post(route('care.assessments.store', $this->patient), [
                'template_code' => 'nihss',
            ])
            ->assertRedirect();

        $this->assertSame(1, Assessment::count());
    }

    public function test_start_is_idempotent_for_same_draft(): void
    {
        $this->setMemberRole('doctor');

        $this->actingAs($this->user)
            ->post(route('care.assessments.store', $this->patient), ['template_code' => 'nihss'])
            ->assertRedirect();

        $first = Assessment::first();

        $this->actingAs($this->user)
            ->post(route('care.assessments.store', $this->patient), ['template_code' => 'nihss'])
            ->assertRedirect(route('care.assessments.show', $first));

        $this->assertSame(1, Assessment::count());
    }

    public function test_save_answers_complete_and_immutable(): void
    {
        $this->setMemberRole('doctor');

        $this->actingAs($this->user)
            ->post(route('care.assessments.store', $this->patient), ['template_code' => 'universal_intake'])
            ->assertRedirect();

        $assessment = Assessment::first();

        $this->actingAs($this->user)
            ->put(route('care.assessments.update', $assessment), [
                'answers' => [
                    'chief_complaint' => 'Headache',
                    'pain_score' => 4,
                ],
                'notes' => 'Initial',
            ])
            ->assertRedirect(route('care.assessments.show', $assessment));

        $this->assertDatabaseHas('care_assessment_answers', [
            'assessment_id' => $assessment->id,
            'value_text' => 'Headache',
        ]);
        $this->assertDatabaseHas('care_assessment_answers', [
            'assessment_id' => $assessment->id,
            'value_number' => 4,
        ]);

        $this->actingAs($this->user)
            ->post(route('care.assessments.complete', $assessment))
            ->assertRedirect();

        $assessment->refresh();
        $this->assertSame(Assessment::STATUS_COMPLETED, $assessment->status);
        $this->assertNotNull($assessment->completed_at);
        $this->assertDatabaseHas('care_audit_logs', ['action' => 'assessment.completed']);

        $this->actingAs($this->user)
            ->put(route('care.assessments.update', $assessment), [
                'answers' => ['chief_complaint' => 'Changed'],
            ])
            ->assertSessionHasErrors('status');

        $this->actingAs($this->user)
            ->post(route('care.assessments.complete', $assessment))
            ->assertSessionHasErrors('status');
    }

    public function test_complete_requires_required_answers(): void
    {
        $this->setMemberRole('nurse');

        $this->actingAs($this->user)
            ->post(route('care.assessments.store', $this->patient), ['template_code' => 'universal_intake'])
            ->assertRedirect();

        $assessment = Assessment::first();

        $this->actingAs($this->user)
            ->post(route('care.assessments.complete', $assessment))
            ->assertSessionHasErrors('answers.chief_complaint');

        $this->assertSame(Assessment::STATUS_DRAFT, $assessment->fresh()->status);
    }

    public function test_cancel_draft_only(): void
    {
        $this->setMemberRole('doctor');

        $this->actingAs($this->user)
            ->post(route('care.assessments.store', $this->patient), ['template_code' => 'universal_intake'])
            ->assertRedirect();

        $assessment = Assessment::first();

        $this->actingAs($this->user)
            ->post(route('care.assessments.cancel', $assessment))
            ->assertRedirect(route('care.assessments.index', $this->patient));

        $this->assertSame(Assessment::STATUS_CANCELLED, $assessment->fresh()->status);
        $this->assertDatabaseHas('care_audit_logs', ['action' => 'assessment.cancelled']);
    }

    public function test_doctor_can_view_consultation_scoped_assessments_index(): void
    {
        $this->setMemberRole('doctor');

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

        $consultation = Consultation::create([
            'owner_ref' => $this->user->public_id,
            'visit_id' => $visit->id,
            'patient_id' => $this->patient->id,
            'status' => Consultation::STATUS_DRAFT,
            'started_at' => now(),
        ]);

        $this->actingAs($this->user)
            ->get(route('care.consultations.assessments.index', $consultation))
            ->assertOk()
            ->assertSee('Clinical assessments')
            ->assertSee($this->patient->fullName());

        // Path shape matches care.ladill.com/consultations/{uuid}/assessments
        $this->actingAs($this->user)
            ->get('/consultations/'.$consultation->uuid.'/assessments')
            ->assertOk();
    }

    public function test_consultation_assessments_allow_patient_home_branch_mismatch(): void
    {
        $this->setMemberRole('doctor');

        $homeBranch = Branch::create([
            'owner_ref' => $this->user->public_id,
            'organization_id' => $this->organization->id,
            'name' => 'Home Branch',
            'code' => 'HOME',
            'is_active' => true,
        ]);
        $this->patient->update(['branch_id' => $homeBranch->id]);

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

        $consultation = Consultation::create([
            'owner_ref' => $this->user->public_id,
            'visit_id' => $visit->id,
            'patient_id' => $this->patient->id,
            'status' => Consultation::STATUS_DRAFT,
            'started_at' => now(),
        ]);

        $this->assertNotSame($homeBranch->id, $this->branch->id);

        $this->actingAs($this->user)
            ->get(route('care.consultations.assessments.index', $consultation))
            ->assertOk();

        $this->actingAs($this->user)
            ->post(route('care.consultations.assessments.store', $consultation), [
                'template_code' => 'universal_intake',
            ])
            ->assertRedirect();

        $assessment = Assessment::first();
        $this->assertNotNull($assessment);
        $this->assertSame($this->branch->id, $assessment->branch_id);
    }

    public function test_consultation_scoped_start_links_consultation_and_visit(): void
    {
        $this->setMemberRole('doctor');

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

        $consultation = Consultation::create([
            'owner_ref' => $this->user->public_id,
            'visit_id' => $visit->id,
            'patient_id' => $this->patient->id,
            'status' => Consultation::STATUS_DRAFT,
            'started_at' => now(),
        ]);

        $this->actingAs($this->user)
            ->post(route('care.consultations.assessments.store', $consultation), [
                'template_code' => 'universal_intake',
            ])
            ->assertRedirect();

        $assessment = Assessment::first();
        $this->assertSame($consultation->id, $assessment->consultation_id);
        $this->assertSame($visit->id, $assessment->visit_id);
        $this->assertSame($this->branch->id, $assessment->branch_id);
    }

    public function test_consultation_create_show_and_store_open_forms_for_doctor(): void
    {
        $this->setMemberRole('doctor');

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

        $consultation = Consultation::create([
            'owner_ref' => $this->user->public_id,
            'visit_id' => $visit->id,
            'patient_id' => $this->patient->id,
            'status' => Consultation::STATUS_DRAFT,
            'started_at' => now(),
        ]);

        // Nested create (was unmatched → Laravel 404 before this fix)
        $this->actingAs($this->user)
            ->get(route('care.consultations.assessments.create', $consultation))
            ->assertOk()
            ->assertSee('Start assessment')
            ->assertSee('Universal Intake');

        $this->actingAs($this->user)
            ->get('/consultations/'.$consultation->uuid.'/assessments/create')
            ->assertOk();

        $response = $this->actingAs($this->user)
            ->post(route('care.consultations.assessments.store', $consultation), [
                'template_code' => 'universal_intake',
            ]);

        $assessment = Assessment::first();
        $this->assertNotNull($assessment);

        $response->assertRedirect(route('care.consultations.assessments.show', [
            'consultation' => $consultation,
            'assessment' => $assessment,
        ]));

        // Nested show (was unmatched → Laravel 404)
        $this->actingAs($this->user)
            ->get(route('care.consultations.assessments.show', [$consultation, $assessment]))
            ->assertOk()
            ->assertSee('Universal Intake')
            ->assertSee('Back to consultation');

        $this->actingAs($this->user)
            ->get('/consultations/'.$consultation->uuid.'/assessments/'.$assessment->uuid)
            ->assertOk();

        // Flat show still works for patient-chart / bookmarks
        $this->actingAs($this->user)
            ->get(route('care.assessments.show', $assessment))
            ->assertOk();

        // Patient create + store with consultation_uuid also lands on nested show
        $this->actingAs($this->user)
            ->get(route('care.assessments.create', [
                'patient' => $this->patient,
                'consultation_uuid' => $consultation->uuid,
            ]))
            ->assertOk();
    }

    public function test_public_bodies_use_consultation_uuid(): void
    {
        $this->setMemberRole('doctor');

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

        $consultation = Consultation::create([
            'owner_ref' => $this->user->public_id,
            'visit_id' => $visit->id,
            'patient_id' => $this->patient->id,
            'status' => Consultation::STATUS_DRAFT,
            'started_at' => now(),
        ]);

        $this->actingAs($this->user)
            ->post(route('care.assessments.store', $this->patient), [
                'template_code' => 'universal_intake',
                'consultation_uuid' => $consultation->uuid,
            ])
            ->assertRedirect();

        $assessment = Assessment::first();
        $this->assertSame($consultation->id, $assessment->consultation_id);

        $this->actingAs($this->user)
            ->get(route('care.consultations.assessments.show', [$consultation, $assessment]))
            ->assertOk();
    }

    public function test_tenant_isolation_returns_404(): void
    {
        $this->setMemberRole('doctor');

        $otherUser = User::create([
            'public_id' => 'other-owner',
            'name' => 'Other',
            'email' => 'other@example.com',
        ]);
        $otherOrg = Organization::create([
            'owner_ref' => $otherUser->public_id,
            'name' => 'Other Clinic',
            'slug' => 'other-clinic',
            'timezone' => 'UTC',
            'settings' => ['onboarded' => true, 'rollout' => [CareFeatures::ASSESSMENTS_ENGINE => true]],
        ]);
        Member::create([
            'owner_ref' => $otherUser->public_id,
            'organization_id' => $otherOrg->id,
            'user_ref' => $otherUser->public_id,
            'role' => 'doctor',
        ]);
        $otherPatient = Patient::create([
            'uuid' => (string) Str::uuid(),
            'owner_ref' => $otherUser->public_id,
            'organization_id' => $otherOrg->id,
            'patient_number' => 'LC-OTHER',
            'first_name' => 'Other',
            'last_name' => 'Patient',
        ]);

        $this->actingAs($this->user)
            ->get(route('care.assessments.index', $otherPatient))
            ->assertNotFound();
    }

    public function test_score_item_stores_numeric_score_from_choice_code(): void
    {
        $this->setMemberRole('doctor');

        $this->actingAs($this->user)
            ->post(route('care.assessments.store', $this->patient), ['template_code' => 'nihss'])
            ->assertRedirect();

        $assessment = Assessment::first();

        $this->actingAs($this->user)
            ->put(route('care.assessments.update', $assessment), [
                'answers' => ['loc' => '2'],
            ])
            ->assertRedirect();

        $this->assertDatabaseHas('care_assessment_answers', [
            'assessment_id' => $assessment->id,
            'value_number' => 2,
            'value_text' => null,
        ]);
    }

    public function test_receptionist_cannot_view_assessments(): void
    {
        $this->setMemberRole('receptionist');

        $this->actingAs($this->user)
            ->get(route('care.assessments.index', $this->patient))
            ->assertForbidden();
    }
}
