<?php

namespace Tests\Feature;

use App\Campaigns\Targeting\CountryCatalog;
use App\Campaigns\Targeting\CountryLookup;
use App\Models\AllowedAdAccount;
use App\Services\Meta\MetaException;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;

class CountryProviderRequestsTest extends TestCase
{
    use RefreshDatabase;

    public function test_meta_resolves_a_country_from_the_geolocation_search_response(): void
    {
        AllowedAdAccount::factory()->meta('act_123')->create();
        config(['platforms.meta.token' => 'test-token', 'platforms.meta.version' => 'v25.0']);
        Http::preventStrayRequests();
        Http::fake([
            'https://graph.facebook.com/v25.0/search*' => Http::response(['data' => [
                ['key' => 'CA', 'type' => 'country', 'name' => 'Canada'],
            ]]),
        ]);

        $result = app(CountryLookup::class)->find('meta', 'CA', 'Canada', 'act_123');

        $this->assertSame(['id' => 'CA', 'name' => 'Canada'], $result);
        Http::assertSent(function (Request $request): bool {
            parse_str((string) parse_url($request->url(), PHP_URL_QUERY), $query);

            return $request->method() === 'GET'
                && ($query['type'] ?? null) === 'adgeolocation'
                && ($query['q'] ?? null) === 'Canada'
                && json_decode((string) ($query['location_types'] ?? ''), true) === ['country'];
        });
        Http::assertSentCount(1);
    }

    public function test_linkedin_resolves_only_the_exact_country_geo_urn(): void
    {
        AllowedAdAccount::factory()->linkedin('123')->create();
        config(['platforms.linkedin.token' => 'test-token', 'platforms.linkedin.version' => '202609']);
        Http::preventStrayRequests();
        Http::fake([
            'https://api.linkedin.com/rest/adTargetingEntities*' => Http::response(['elements' => [
                ['urn' => 'urn:li:geo:102095887', 'name' => 'California, United States'],
                ['urn' => 'urn:li:geo:999', 'name' => 'Canada'],
            ]]),
        ]);

        $result = app(CountryLookup::class)->find('linkedin', 'CA', 'Canada', '123');

        $this->assertSame(['id' => 'urn:li:geo:999', 'name' => 'Canada'], $result);
        Http::assertSent(function (Request $request): bool {
            parse_str((string) parse_url($request->url(), PHP_URL_QUERY), $query);

            return $request->method() === 'GET'
                && ($query['q'] ?? null) === 'typeahead'
                && ($query['facet'] ?? null) === 'urn:li:adTargetingFacet:locations'
                && ($query['queryVersion'] ?? null) === 'QUERY_USES_URNS'
                && ($query['query'] ?? null) === 'Canada'
                && ! array_key_exists('locale.language', $query)
                && ! array_key_exists('locale.country', $query);
        });
        Http::assertSentCount(1);
    }

    public function test_google_resolves_an_enabled_country_by_iso_code(): void
    {
        AllowedAdAccount::factory()->google('1234567890')->create();
        config([
            'services.google_ads.refresh_token' => 'test-refresh-token',
            'services.google_ads.customer_id' => '123-456-7890',
            'services.google_ads.oauth_client_id' => 'test-client',
            'services.google_ads.oauth_client_secret' => 'test-secret',
            'services.google_ads.developer_token' => 'test-developer-token',
            'services.google_ads.api_version' => 'v25',
        ]);
        Http::preventStrayRequests();
        Http::fake([
            'https://oauth2.googleapis.com/token' => Http::response(['access_token' => 'test-access-token']),
            'https://googleads.googleapis.com/v25/customers/1234567890/googleAds:searchStream' => Http::response([['results' => [
                ['geoTargetConstant' => ['resourceName' => 'geoTargetConstants/2124', 'name' => 'Canada', 'countryCode' => 'CA', 'targetType' => 'Country', 'status' => 'ENABLED']],
            ]]]),
        ]);

        $result = app(CountryLookup::class)->find('google', 'CA', 'Canada', '1234567890');

        $this->assertSame(['id' => 'geoTargetConstants/2124', 'name' => 'Canada'], $result);
        Http::assertSent(fn (Request $request): bool => $request->method() === 'POST'
            && str_contains($request->url(), '/googleAds:searchStream')
            && str_contains((string) ($request->data()['query'] ?? ''), "geo_target_constant.country_code = 'CA'")
            && str_contains((string) ($request->data()['query'] ?? ''), "geo_target_constant.target_type = 'Country'"));
        Http::assertSentCount(2);
    }

    public function test_provider_authentication_failure_does_not_save_a_mapping(): void
    {
        AllowedAdAccount::factory()->meta('act_123')->create();
        config(['platforms.meta.token' => 'expired-token', 'platforms.meta.version' => 'v25.0']);
        Http::preventStrayRequests();
        Http::fake([
            'https://graph.facebook.com/v25.0/search*' => Http::response([
                'error' => ['message' => 'Invalid OAuth access token', 'type' => 'OAuthException', 'code' => 190],
            ], 401),
        ]);

        try {
            app(CountryCatalog::class)->resolve('meta', ['CA'], 'act_123');
            $this->fail('An authentication failure must stop country resolution.');
        } catch (MetaException $exception) {
            $this->assertStringContainsString('Invalid OAuth access token', $exception->getMessage());
        }

        $this->assertDatabaseCount('platform_locations', 0);
        Http::assertSentCount(1);
    }
}
