<?php

namespace Tests\Feature;

use App\Agent\Choices;
use App\Agent\ToolRegistry;
use App\Agent\Workspace;
use App\Campaigns\Targeting\LocationDiscovery;
use App\Models\AllowedAdAccount;
use App\Models\Campaign;
use App\Models\GoogleAdsConnection;
use App\Models\Location;
use App\Models\User;
use App\Services\GoogleAdsService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;
use InvalidArgumentException;
use Laravel\Ai\Tools\Request as ToolRequest;
use Tests\TestCase;

class GoogleLocationSearchTest extends TestCase
{
    use RefreshDatabase;

    private function configuredConnection(): GoogleAdsConnection
    {
        AllowedAdAccount::factory()->google('1234567890')->create();
        config([
            'services.google_ads.refresh_token' => 'test-refresh-token',
            'services.google_ads.customer_id' => '1234567890',
            'services.google_ads.oauth_client_id' => 'test-client',
            'services.google_ads.oauth_client_secret' => 'test-secret',
            'services.google_ads.developer_token' => 'test-developer-token',
        ]);

        return GoogleAdsConnection::shared();
    }

    public function test_city_search_keeps_ambiguous_locations_distinct_and_filters_unsupported_results(): void
    {
        $connection = $this->configuredConnection();
        Http::preventStrayRequests();
        Http::fake([
            'https://oauth2.googleapis.com/token' => Http::response(['access_token' => 'test-access-token']),
            'https://googleads.googleapis.com/*' => Http::response([['results' => [
                ['geoTargetConstant' => ['resourceName' => 'geoTargetConstants/1', 'name' => 'Springfield', 'canonicalName' => 'Springfield, Illinois, United States', 'countryCode' => 'US', 'targetType' => 'City', 'status' => 'ENABLED']],
                ['geoTargetConstant' => ['resourceName' => 'geoTargetConstants/2', 'name' => 'Springfield', 'canonicalName' => 'Springfield, Missouri, United States', 'countryCode' => 'US', 'targetType' => 'City', 'status' => 'ENABLED']],
                ['geoTargetConstant' => ['resourceName' => 'geoTargetConstants/3', 'name' => 'Springfield', 'countryCode' => 'CA', 'targetType' => 'City', 'status' => 'ENABLED']],
                ['geoTargetConstant' => ['resourceName' => 'geoTargetConstants/4', 'name' => 'Springfield', 'countryCode' => 'US', 'targetType' => 'City', 'status' => 'REMOVAL_PLANNED']],
                ['geoTargetConstant' => ['resourceName' => 'geoTargetConstants/5', 'name' => 'Springfield', 'countryCode' => 'US', 'targetType' => 'City', 'status' => 'ENABLED']],
            ]]]),
        ]);

        $results = app(GoogleAdsService::class)->geoTargetCandidates($connection, 'city', 'US', 'Springfield');

        $this->assertSame(['geoTargetConstants/1', 'geoTargetConstants/2'], array_column($results, 'id'));
        $this->assertSame(['Springfield, Illinois, United States', 'Springfield, Missouri, United States'], array_column($results, 'label'));
        Http::assertSent(fn (Request $request): bool => str_contains($request->url(), 'googleAds:searchStream')
            && str_contains((string) ($request->data()['query'] ?? ''), "geo_target_constant.country_code = 'US'")
            && str_contains((string) ($request->data()['query'] ?? ''), "geo_target_constant.name LIKE '%Springfield%'")
            && str_contains((string) ($request->data()['query'] ?? ''), "geo_target_constant.target_type IN ('City')"));
    }

    public function test_invalid_search_is_rejected_before_a_provider_call(): void
    {
        $connection = $this->configuredConnection();
        Http::fake();

        $this->expectException(InvalidArgumentException::class);
        try {
            app(GoogleAdsService::class)->geoTargetCandidates($connection, 'city', 'US', "Austin' OR status='ENABLED");
        } finally {
            Http::assertNothingSent();
        }
    }

    public function test_city_search_can_be_narrowed_by_state_and_selected_by_exact_id(): void
    {
        $this->configuredConnection();
        Location::factory()->create(['iso_code' => 'US', 'country_code' => 'US', 'source_key' => 'US']);
        Http::preventStrayRequests();
        Http::fake([
            'https://oauth2.googleapis.com/token' => Http::response(['access_token' => 'test-access-token']),
            'https://googleads.googleapis.com/*' => Http::response([['results' => [
                ['geoTargetConstant' => [
                    'resourceName' => 'geoTargetConstants/123',
                    'name' => 'Springfield',
                    'canonicalName' => 'Springfield, Illinois, United States',
                    'countryCode' => 'US',
                    'targetType' => 'City',
                    'status' => 'ENABLED',
                ]],
            ]]]),
        ]);

        $discovery = app(LocationDiscovery::class);
        $matches = $discovery->search('google', 'city', 'US', 'Springfield, Illinois', '1234567890');

        $this->assertSame(['geoTargetConstants/123'], array_column($matches, 'external_id'));
        Http::assertSent(fn (Request $request): bool => str_contains($request->url(), 'googleAds:searchStream')
            && str_contains((string) ($request->data()['query'] ?? ''), "geo_target_constant.name LIKE '%Springfield%'")
            && str_contains((string) ($request->data()['query'] ?? ''), "geo_target_constant.canonical_name LIKE '%Illinois%'"));

        $selected = $discovery->select('google', 'city', 'US', 'Springfield, Illinois', 'geoTargetConstants/123', '1234567890');

        $this->assertSame('geoTargetConstants/123', $selected->external_id);
        $this->assertSame('google', $selected->platform);
    }

    public function test_google_chat_offers_ambiguous_places_and_saves_the_chosen_one(): void
    {
        $this->configuredConnection();
        Location::factory()->create(['iso_code' => 'US', 'country_code' => 'US', 'source_key' => 'US']);
        $user = User::factory()->create();
        $this->actingAs($user);
        $campaign = Campaign::create([
            'user_id' => $user->getKey(),
            'name' => 'Google local',
            'platform' => 'google',
            'status' => 'draft',
            'ad_account_id' => '1234567890',
            'locations' => ['countries' => ['US']],
        ]);
        app(Workspace::class)->bindTo('conv-google-local');
        app(Workspace::class)->focusOn($campaign);

        Http::preventStrayRequests();
        Http::fake([
            'https://oauth2.googleapis.com/token' => Http::response(['access_token' => 'test-access-token']),
            'https://googleads.googleapis.com/*' => Http::response([['results' => [
                ['geoTargetConstant' => ['resourceName' => 'geoTargetConstants/111', 'name' => 'Springfield', 'canonicalName' => 'Springfield, Illinois, United States', 'countryCode' => 'US', 'targetType' => 'City', 'status' => 'ENABLED']],
                ['geoTargetConstant' => ['resourceName' => 'geoTargetConstants/222', 'name' => 'Springfield', 'canonicalName' => 'Springfield, Missouri, United States', 'countryCode' => 'US', 'targetType' => 'City', 'status' => 'ENABLED']],
            ]]]),
        ]);

        $tool = collect(app(ToolRegistry::class)->resolve())->first(fn ($candidate): bool => $candidate->name() === 'campaign__choose_location');
        $this->assertNotNull($tool);
        $search = json_decode((string) $tool->handle(new ToolRequest(['country_code' => 'US', 'kind' => 'city', 'query' => 'Springfield'])), true);

        $this->assertTrue($search['ok']);
        $this->assertSame('google_location', app(Choices::class)->all()[0]['field']);
        $this->assertSame(['Springfield, Illinois, United States', 'Springfield, Missouri, United States'], array_column(app(Choices::class)->all()[0]['options'], 'label'));

        $selected = json_decode((string) $tool->handle(new ToolRequest([
            'country_code' => 'US', 'kind' => 'city', 'query' => 'Springfield',
            'external_id' => 'geoTargetConstants/222', 'expected_revision' => $search['revision'],
        ])), true);

        $this->assertTrue($selected['ok']);
        $this->assertSame('geoTargetConstants/222', $campaign->fresh()->targetingSet->locations()->where('kind', 'city')->first()->platformLocation->external_id);
    }
}
