<?php

namespace Tests\Unit\Services\AI;

use App\Exceptions\ProviderNotConfiguredException;
use App\Services\AI\ApifyMetaAdLibraryProvider;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Sleep;
use RuntimeException;
use Tests\TestCase;

class ApifyMetaAdLibraryProviderTest extends TestCase
{
    public function test_search_starts_an_async_apify_run_with_the_brand_keyword_country_and_media_type(): void
    {
        $this->fakeApifyResponse();

        (new ApifyMetaAdLibraryProvider)->search('Nike', 'IN', null, 'VIDEO');

        Http::assertSent(function ($request): bool {
            $payload = $request->data();

            return str_contains($request->url(), 'acts/sukhdipp~meta-ad-library-scraper/runs')
                && ! str_contains($request->url(), 'run-sync')
                && str_contains($request->url(), 'token=test-apify-token')
                && $request->method() === 'POST'
                && $payload['searchTerms'] === ['Nike']
                && $payload['countries'] === ['IN']
                && $payload['mediaType'] === 'video'
                && $payload['activeStatus'] === 'active';
        });
    }

    public function test_search_maps_apify_ads_for_the_wizard_cards(): void
    {
        $this->fakeApifyResponse([
            [
                'id' => '1249043200627555',
                'pageName' => 'Nike',
                'title' => 'Nike: Shoes, Apparel & Stories',
                'body' => 'Celebrate your birthday with Nike.',
                'ctaText' => 'Shop now',
                'linkDomain' => 'nike.com',
                'startDate' => '2026-03-17',
                'totalActiveDays' => 10,
                'images' => [['resizedUrl' => 'https://cdn.example/thumb.jpg']],
                'videos' => [],
                'platforms' => ['FACEBOOK'],
                'adLibraryUrl' => 'https://www.facebook.com/ads/library/?id=1249043200627555',
            ],
        ]);

        $ad = (new ApifyMetaAdLibraryProvider)->search('Nike')->first();

        $this->assertSame('1249043200627555', $ad->externalAdId);
        $this->assertSame('Nike', $ad->advertiserName);
        $this->assertSame('https://cdn.example/thumb.jpg', $ad->thumbnailUrl);
        $this->assertSame(['Celebrate your birthday with Nike.'], $ad->snapshot['ad_creative_bodies']);
        $this->assertSame(['Nike: Shoes, Apparel & Stories'], $ad->snapshot['ad_creative_link_titles']);
        $this->assertSame(['nike.com'], $ad->snapshot['ad_creative_link_captions']);
        $this->assertSame('https://www.facebook.com/ads/library/?id=1249043200627555', $ad->snapshot['ad_snapshot_url']);
        $this->assertSame('2026-03-17', $ad->snapshot['ad_delivery_start_time']);
    }

    public function test_search_returns_ads_with_the_longest_run_first(): void
    {
        $this->fakeApifyResponse([
            ['id' => 'old', 'pageName' => 'A', 'body' => 'Old ad', 'totalActiveDays' => 2, 'images' => [], 'videos' => [], 'platforms' => ['FACEBOOK']],
            ['id' => 'new', 'pageName' => 'B', 'body' => 'New ad', 'totalActiveDays' => 40, 'images' => [], 'videos' => [], 'platforms' => ['FACEBOOK']],
        ]);

        $results = (new ApifyMetaAdLibraryProvider)->search('Nike');

        $this->assertSame(['new', 'old'], $results->pluck('externalAdId')->all());
    }

    public function test_search_by_page_sends_page_ids_instead_of_search_terms(): void
    {
        $this->fakeApifyResponse();

        (new ApifyMetaAdLibraryProvider)->searchByPage(['15087023444'], 'US', null, 'IMAGE');

        Http::assertSent(function ($request): bool {
            $payload = $request->data();

            return ($payload['pageIds'] ?? null) === ['15087023444']
                && ($payload['mediaType'] ?? null) === 'image'
                && ! isset($payload['searchTerms']);
        });
    }

    public function test_collect_run_returns_null_while_the_actor_is_running(): void
    {
        config(['services.apify.token' => 'test-apify-token']);
        Http::preventStrayRequests();
        Http::fake([
            'https://api.apify.com/v2/actor-runs/*' => Http::response([
                'data' => ['id' => 'run-1', 'status' => 'RUNNING', 'defaultDatasetId' => 'ds-1'],
            ]),
        ]);

        $this->assertNull((new ApifyMetaAdLibraryProvider)->collectRun('run-1'));
    }

    public function test_collect_run_throws_when_the_actor_fails(): void
    {
        config(['services.apify.token' => 'test-apify-token']);
        Http::preventStrayRequests();
        Http::fake([
            'https://api.apify.com/v2/actor-runs/*' => Http::response([
                'data' => ['id' => 'run-1', 'status' => 'FAILED', 'defaultDatasetId' => 'ds-1'],
            ]),
        ]);

        $this->expectException(RuntimeException::class);

        (new ApifyMetaAdLibraryProvider)->collectRun('run-1');
    }

    public function test_search_throws_when_the_apify_token_is_missing(): void
    {
        config(['services.apify.token' => null]);

        $this->expectException(ProviderNotConfiguredException::class);

        (new ApifyMetaAdLibraryProvider)->search('Nike');
    }

    /**
     * @param  list<array<string, mixed>>  $ads
     */
    private function fakeApifyResponse(array $ads = []): void
    {
        config(['services.apify.token' => 'test-apify-token']);
        Sleep::fake();

        $ads = $ads !== [] ? $ads : [
            ['id' => '1', 'pageName' => 'Acme', 'images' => [], 'videos' => [], 'platforms' => ['FACEBOOK'], 'totalActiveDays' => 1],
        ];

        Http::preventStrayRequests();
        Http::fake(function ($request) use ($ads) {
            $url = $request->url();

            if ($request->method() === 'POST' && str_contains($url, '/acts/') && str_contains($url, '/runs')) {
                return Http::response([
                    'data' => [
                        'id' => 'run-1',
                        'status' => 'RUNNING',
                        'defaultDatasetId' => 'ds-1',
                    ],
                ], 201);
            }

            if (str_contains($url, '/actor-runs/run-1')) {
                return Http::response([
                    'data' => [
                        'id' => 'run-1',
                        'status' => 'SUCCEEDED',
                        'defaultDatasetId' => 'ds-1',
                    ],
                ]);
            }

            if (str_contains($url, '/datasets/ds-1/items')) {
                return Http::response($ads);
            }

            return Http::response(['error' => 'unexpected '.$url], 500);
        });
    }
}
