<?php

namespace Tests\Feature;

use App\Http\Middleware\EnsurePlatformSession;
use App\Models\Branch;
use App\Models\Member;
use App\Models\MessagingCredential;
use App\Models\Organization;
use App\Models\Patient;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;

class CareMessagingIntegrationsTest extends TestCase
{
    use RefreshDatabase;

    protected User $user;

    protected Organization $organization;

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

        $this->user = User::create([
            'public_id' => 'test-user-msg-001',
            'name' => 'Test User',
            'email' => 'msg@example.com',
        ]);

        $this->organization = Organization::create([
            'owner_ref' => $this->user->public_id,
            'name' => 'Test Clinic',
            'slug' => 'test-clinic-msg',
            'timezone' => 'UTC',
            'settings' => ['onboarded' => true, 'facility_type' => 'clinic'],
        ]);

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

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

    public function test_integrations_page_loads(): void
    {
        $this->actingAs($this->user)
            ->get(route('care.integrations'))
            ->assertOk()
            ->assertSee('SMS')
            ->assertSee('Email')
            ->assertSee('credentials for outbound messaging');
    }

    public function test_saving_sms_credentials_encrypts_key(): void
    {
        Http::fake([
            '*/api/sms/me' => Http::response([
                'api_key_prefix' => 'lsk_sms_live_abcd',
                'service_id' => 1,
                'status' => 'active',
                'brand_name' => 'Clinic',
            ]),
            '*/api/sms/senders' => Http::response([
                'data' => [['id' => 1, 'sender_id' => 'ClinicA', 'is_default' => true]],
                'default_sender' => 'Ladill',
            ]),
        ]);

        $plain = 'lsk_sms_live_'.str_repeat('a', 32);

        $this->actingAs($this->user)
            ->post(route('care.integrations.sms.save'), [
                'sms_api_key' => $plain,
                'sms_sender_id' => 'ClinicA',
            ])
            ->assertRedirect()
            ->assertSessionHas('success');

        $row = MessagingCredential::query()->where('organization_id', $this->organization->id)->first();
        $this->assertNotNull($row);
        $this->assertNotSame($plain, $row->sms_api_key_encrypted);
        $this->assertSame($plain, Crypt::decryptString($row->sms_api_key_encrypted));
        $this->assertSame(MessagingCredential::STATUS_VALID, $row->sms_status);
        $this->assertSame('ClinicA', $row->sms_sender_id);
    }

    public function test_invalid_sms_key_is_rejected(): void
    {
        Http::fake([
            '*/api/sms/me' => Http::response(['error' => 'Invalid or missing API key.'], 401),
        ]);

        $this->actingAs($this->user)
            ->post(route('care.integrations.sms.save'), [
                'sms_api_key' => 'lsk_sms_live_'.str_repeat('b', 32),
                'sms_sender_id' => 'ClinicA',
            ])
            ->assertRedirect()
            ->assertSessionHas('error');
    }

    public function test_patient_sms_requires_credentials(): void
    {
        $patient = Patient::create([
            'uuid' => (string) \Illuminate\Support\Str::uuid(),
            'owner_ref' => $this->user->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => Branch::first()->id,
            'patient_number' => 'LC-MSG-00001',
            'first_name' => 'Ada',
            'last_name' => 'Lovelace',
            'phone' => '+233201111111',
        ]);

        $this->actingAs($this->user)
            ->post(route('care.patients.sms', $patient), ['message' => 'Hello'])
            ->assertRedirect()
            ->assertSessionHas('error');
    }

    public function test_patient_sms_uses_customer_relay_key(): void
    {
        $plain = 'lsk_sms_live_'.str_repeat('c', 32);
        MessagingCredential::create([
            'owner_ref' => $this->user->public_id,
            'organization_id' => $this->organization->id,
            'sms_api_key_encrypted' => Crypt::encryptString($plain),
            'sms_api_key_prefix' => substr($plain, 0, 16),
            'sms_sender_id' => 'ClinicA',
            'sms_status' => MessagingCredential::STATUS_VALID,
            'sms_validated_at' => now(),
        ]);

        Http::fake([
            '*/api/sms/send' => Http::response(['success' => true, 'message_id' => 1]),
        ]);

        $patient = Patient::create([
            'uuid' => (string) \Illuminate\Support\Str::uuid(),
            'owner_ref' => $this->user->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => Branch::first()->id,
            'patient_number' => 'LC-MSG-00002',
            'first_name' => 'Ada',
            'last_name' => 'Lovelace',
            'phone' => '+233201111111',
        ]);

        $this->actingAs($this->user)
            ->post(route('care.patients.sms', $patient), ['message' => 'Hello patient'])
            ->assertRedirect()
            ->assertSessionHas('success');

        Http::assertSent(function ($request) use ($plain) {
            return str_contains($request->url(), '/api/sms/send')
                && $request->hasHeader('Authorization', 'Bearer '.$plain)
                && $request['sender_id'] === 'ClinicA'
                && $request['text'] === 'Hello patient';
        });
    }

    public function test_patient_email_uses_customer_bird_key(): void
    {
        $plain = 'lsk_live_'.str_repeat('d', 32);
        MessagingCredential::create([
            'owner_ref' => $this->user->public_id,
            'organization_id' => $this->organization->id,
            'bird_api_key_encrypted' => Crypt::encryptString($plain),
            'bird_api_key_prefix' => substr($plain, 0, 16),
            'bird_from_email' => 'clinic@example.test',
            'bird_from_name' => 'Clinic',
            'bird_status' => MessagingCredential::STATUS_VALID,
            'bird_validated_at' => now(),
        ]);

        Http::fake([
            '*/api/smtp/send' => Http::response(['success' => true, 'message_id' => 'x']),
        ]);

        $patient = Patient::create([
            'uuid' => (string) \Illuminate\Support\Str::uuid(),
            'owner_ref' => $this->user->public_id,
            'organization_id' => $this->organization->id,
            'branch_id' => Branch::first()->id,
            'patient_number' => 'LC-MSG-00003',
            'first_name' => 'Ada',
            'last_name' => 'Lovelace',
            'email' => 'ada@example.com',
        ]);

        $this->actingAs($this->user)
            ->post(route('care.patients.email', $patient), [
                'subject' => 'Hi',
                'body' => 'Body text',
            ])
            ->assertRedirect()
            ->assertSessionHas('success');

        Http::assertSent(function ($request) use ($plain) {
            return str_contains($request->url(), '/api/smtp/send')
                && $request->hasHeader('Authorization', 'Bearer '.$plain)
                && $request['from'] === 'clinic@example.test'
                && $request['from_name'] === 'Clinic';
        });
    }

    public function test_saving_bird_credentials_rejects_acct_prefix(): void
    {
        $this->actingAs($this->user)
            ->post(route('care.integrations.bird.save'), [
                'bird_api_key' => 'lsk_acct_'.str_repeat('a', 32),
                'bird_from_email' => 'clinic@example.test',
                'bird_from_name' => 'Clinic',
            ])
            ->assertRedirect()
            ->assertSessionHas('error');
    }

    public function test_saving_bird_credentials_encrypts_live_key(): void
    {
        Http::fake([
            '*/api/smtp/me' => Http::response([
                'api_key_prefix' => 'lsk_live_abcd1234',
                'status' => 'active',
                'verified_domains' => ['example.test'],
            ]),
        ]);

        $plain = 'lsk_live_'.str_repeat('e', 32);

        $this->actingAs($this->user)
            ->post(route('care.integrations.bird.save'), [
                'bird_api_key' => "  {$plain}\n",
                'bird_from_email' => 'clinic@example.test',
                'bird_from_name' => 'Clinic',
            ])
            ->assertRedirect()
            ->assertSessionHas('success');

        $row = MessagingCredential::query()->where('organization_id', $this->organization->id)->first();
        $this->assertNotNull($row);
        $this->assertSame($plain, Crypt::decryptString($row->bird_api_key_encrypted));
        $this->assertSame(MessagingCredential::STATUS_VALID, $row->bird_status);
        $this->assertSame('clinic@example.test', $row->bird_from_email);
    }

    public function test_saving_bird_credentials_surfaces_platform_401(): void
    {
        Http::fake([
            '*/api/smtp/me' => Http::response(['error' => 'Invalid or missing API key.'], 401),
        ]);

        $this->actingAs($this->user)
            ->post(route('care.integrations.bird.save'), [
                'bird_api_key' => 'lsk_live_'.str_repeat('f', 32),
                'bird_from_email' => 'clinic@example.test',
            ])
            ->assertRedirect()
            ->assertSessionHas('error', 'Invalid or missing API key.');
    }
}
