<?php

namespace Tests\Feature;

use App\Enums\SmsSendStatus;
use App\Jobs\SendSmsToCouponJob;
use App\Models\Coupon;
use App\Models\SmsCampaign;
use App\Models\SmsSendLog;
use App\Models\User;
use App\Services\SmsBroadcastService;
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Queue;
use Tests\TestCase;

class SmsBroadcastServiceTest extends TestCase
{
    use LazilyRefreshDatabase;

    private SmsBroadcastService $service;

    protected function setUp(): void
    {
        parent::setUp();

        Http::fake([
            config('services.sms.url') => Http::response('ok', 200),
        ]);

        $this->service = app(SmsBroadcastService::class);
    }

    public function test_resolve_recipients_for_all_excluding_ids(): void
    {
        $included = Coupon::factory()->count(2)->create();
        $excluded = Coupon::factory()->create();

        $recipients = $this->service->resolveRecipients(
            sendToAll: true,
            excludedIds: [$excluded->id],
        );

        $this->assertCount(2, $recipients);
        $this->assertTrue($recipients->pluck('id')->contains($included->first()->id));
        $this->assertFalse($recipients->pluck('id')->contains($excluded->id));
    }

    public function test_resolve_recipients_for_selected_only(): void
    {
        $selected = Coupon::factory()->create();
        Coupon::factory()->create();

        $recipients = $this->service->resolveRecipients(
            sendToAll: false,
            selectedIds: [$selected->id],
        );

        $this->assertCount(1, $recipients);
        $this->assertSame($selected->id, $recipients->first()->id);
    }

    public function test_start_campaign_queues_chain_and_creates_logs(): void
    {
        Bus::fake();

        $admin = User::factory()->create();
        $coupons = Coupon::factory()->count(2)->create();

        $campaign = $this->service->startCampaign(
            admin: $admin,
            message: 'Test broadcast',
            sendToAll: false,
            selectedIds: $coupons->pluck('id')->all(),
        );

        $this->assertSame(2, $campaign->recipient_count);
        $this->assertDatabaseCount(SmsSendLog::class, 2);
        $this->assertDatabaseHas(SmsSendLog::class, [
            'sms_campaign_id' => $campaign->id,
            'status' => SmsSendStatus::Pending->value,
        ]);

        Bus::assertChained([
            SendSmsToCouponJob::class,
            SendSmsToCouponJob::class,
        ]);
    }

    public function test_invalid_phone_is_skipped_without_queue_job(): void
    {
        Bus::fake();

        $admin = User::factory()->create();
        $invalid = Coupon::factory()->create(['phone' => '81234567']);
        $valid = Coupon::factory()->create();

        $campaign = $this->service->startCampaign(
            admin: $admin,
            message: 'Test',
            sendToAll: false,
            selectedIds: [$invalid->id, $valid->id],
        );

        $this->assertSame(2, $campaign->recipient_count);
        $this->assertSame(1, $campaign->skipped_count);

        $this->assertDatabaseHas(SmsSendLog::class, [
            'coupon_id' => $invalid->id,
            'status' => SmsSendStatus::SkippedInvalid->value,
        ]);

        Bus::assertChained([
            SendSmsToCouponJob::class,
        ]);
    }

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

        $admin = User::factory()->create();
        $coupon = Coupon::factory()->create(['phone' => '61929248']);

        $campaign = SmsCampaign::factory()->create([
            'message' => 'Queued hello',
            'recipient_count' => 1,
            'created_by' => $admin->id,
        ]);

        SmsSendLog::factory()->create([
            'sms_campaign_id' => $campaign->id,
            'coupon_id' => $coupon->id,
            'phone' => $coupon->phone,
            'message' => $campaign->message,
            'status' => SmsSendStatus::Pending,
        ]);

        $job = new SendSmsToCouponJob($campaign, $coupon);
        $job->handle();

        Http::assertSentCount(1);

        $campaign->refresh();

        $this->assertSame(1, $campaign->sent_count);
        $this->assertNotNull($campaign->completed_at);
        $this->assertDatabaseHas(SmsSendLog::class, [
            'sms_campaign_id' => $campaign->id,
            'status' => SmsSendStatus::Sent->value,
        ]);
    }
}
