<?php

namespace Tests\Feature;

use App\Domain\WhatsApp\WhatsAppManager;
use App\Enums\WaMessageStatus;
use App\Models\Patient;
use App\Models\Tenant;
use App\Models\WaMessage;
use App\Support\Tenancy;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Tests\TestCase;

class WhatsAppEngineTest extends TestCase
{
    use RefreshDatabase;

    protected Tenant $tenant;
    protected Patient $patient;

    protected function setUp(): void
    {
        parent::setUp();
        $this->seed();
        config(['whatsapp.driver' => 'log']);

        $this->tenant = Tenant::create(['name' => 'Smile', 'slug' => 'smile', 'default_locale' => 'ar']);
        \App\Domain\WhatsApp\DefaultTemplates::seed($this->tenant);
        app(Tenancy::class)->set($this->tenant);
        $this->patient = Patient::factory()->create(['whatsapp_opt_in' => true]);
    }

    public function test_queue_template_persists_message_and_dispatches_job(): void
    {
        Queue::fake();

        $msg = app(WhatsAppManager::class)->queueTemplate(
            $this->patient, \App\Enums\WaTemplateKey::Recall->value,
            ['reason' => 'check-up', 'link' => 'https://x']
        );

        $this->assertNotNull($msg);
        $this->assertSame(WaMessageStatus::Queued, $msg->status);
        $this->assertStringContainsString('check-up', $msg->body);
        $this->assertStringContainsString($this->patient->full_name, $msg->body);
        Queue::assertPushed(\App\Jobs\SendWhatsAppMessage::class);
    }

    public function test_opted_out_patient_is_skipped_unless_forced(): void
    {
        $this->patient->update(['whatsapp_opt_in' => false]);

        $this->assertNull(app(WhatsAppManager::class)->queueTemplate(
            $this->patient, \App\Enums\WaTemplateKey::Reminder24h->value
        ));
        $this->assertNotNull(app(WhatsAppManager::class)->queueRaw($this->patient, 'manual'));
    }

    public function test_deliver_marks_sent_with_log_driver(): void
    {
        $msg = app(WhatsAppManager::class)->queueRaw($this->patient, 'hello');
        app(WhatsAppManager::class)->deliver($msg->fresh());

        $msg->refresh();
        $this->assertSame(WaMessageStatus::Sent, $msg->status);
        $this->assertNotNull($msg->provider_message_id);
        $this->assertSame(1, $msg->attempts);
    }

    public function test_retryable_failure_schedules_retry_then_fails_after_max(): void
    {
        $msg = app(WhatsAppManager::class)->queueRaw($this->patient, 'x');

        // Force a retryable failure path by swapping in a failing driver.
        $manager = new class(app(\App\Domain\WhatsApp\TemplateRenderer::class), app(Tenancy::class)) extends WhatsAppManager {
            public function driver(): \App\Domain\WhatsApp\Contracts\WhatsAppDriver
            {
                return new class implements \App\Domain\WhatsApp\Contracts\WhatsAppDriver {
                    public function sendText($m): \App\Domain\WhatsApp\SendResult
                    {
                        return \App\Domain\WhatsApp\SendResult::failure('500', 'server', retryable: true);
                    }
                    public function sendDocument($m, $u): \App\Domain\WhatsApp\SendResult
                    {
                        return $this->sendText($m);
                    }
                };
            }
        };

        config(['whatsapp.max_attempts' => 2]);
        $manager->deliver($msg->fresh());
        $this->assertSame(WaMessageStatus::Retrying, $msg->fresh()->status);
        $this->assertNotNull($msg->fresh()->next_attempt_at);

        $manager->deliver($msg->fresh());
        $this->assertSame(WaMessageStatus::Failed, $msg->fresh()->status);
        $this->assertSame('server', $msg->fresh()->failure_reason);
    }

    public function test_sweep_retries_redispatches_due_messages(): void
    {
        Queue::fake();
        WaMessage::factory()->create([
            'tenant_id' => $this->tenant->id,
            'status' => WaMessageStatus::Retrying->value,
            'next_attempt_at' => now()->subMinute(),
        ]);
        WaMessage::factory()->create([
            'tenant_id' => $this->tenant->id,
            'status' => WaMessageStatus::Retrying->value,
            'next_attempt_at' => now()->addHour(), // not due yet
        ]);

        $count = app(WhatsAppManager::class)->sweepRetries();
        $this->assertSame(1, $count);
    }

    public function test_status_webhook_updates_message(): void
    {
        $msg = WaMessage::factory()->create([
            'tenant_id' => $this->tenant->id,
            'status' => WaMessageStatus::Sent->value,
            'provider_message_id' => 'wamid.123',
        ]);

        app(WhatsAppManager::class)->applyStatusUpdate('wamid.123', 'delivered');
        $this->assertSame(WaMessageStatus::Delivered, $msg->fresh()->status);

        app(WhatsAppManager::class)->applyStatusUpdate('wamid.123', 'read');
        $this->assertSame(WaMessageStatus::Read, $msg->fresh()->status);
        $this->assertNotNull($msg->fresh()->read_at);
    }

    public function test_custom_template_override_is_used(): void
    {
        \App\Models\WaTemplate::where('key', 'recall')->update([
            'body_ar' => 'تذكير مخصص لـ {patient}', 'body_en' => 'Custom {patient}',
        ]);

        $msg = app(WhatsAppManager::class)->queueTemplate(
            $this->patient, \App\Enums\WaTemplateKey::Recall->value, ['reason' => 'x', 'link' => 'y']
        );
        $this->assertStringContainsString('تذكير مخصص', $msg->body);
    }

    public function test_disabled_template_is_not_sent(): void
    {
        \App\Models\WaTemplate::where('key', 'reminder_1h')->update(['enabled' => false]);

        $this->assertNull(app(WhatsAppManager::class)->queueTemplate(
            $this->patient, \App\Enums\WaTemplateKey::Reminder1h->value
        ));
    }
}
