<?php

namespace App\Console\Commands;

use App\Services\Keywords\GoogleAdsClientFactory;
use App\Services\Keywords\KeywordCompetitionFormatter;
use Google\Ads\GoogleAds\Lib\V25\GoogleAdsException;
use Google\Ads\GoogleAds\Util\V25\ResourceNames;
use Google\Ads\GoogleAds\V25\Enums\KeywordPlanNetworkEnum\KeywordPlanNetwork;
use Google\Ads\GoogleAds\V25\Services\GenerateKeywordIdeasRequest;
use Google\Ads\GoogleAds\V25\Services\KeywordSeed;
use Google\Ads\GoogleAds\V25\Services\ListAccessibleCustomersRequest;
use Illuminate\Console\Attributes\Description;
use Illuminate\Console\Attributes\Signature;
use Illuminate\Console\Command;
use InvalidArgumentException;
use Throwable;

#[Signature('keywords:test-connection {--seed=office chair : Seed keyword for a sample Keyword Planner request} {--limit=5 : Number of keyword ideas to print}')]
#[Description('Verify Google Ads credentials and Keyword Planner access')]
class TestKeywordResearchConnectionCommand extends Command
{
    public function handle(GoogleAdsClientFactory $clientFactory): int
    {
        $missing = $clientFactory->missingConfigurationKeys();

        if ($missing !== []) {
            $this->components->error('Missing Google Ads credentials in .env: '.implode(', ', $missing));
            $this->line('Copy your legacy ini values into .env, then run: php artisan config:clear');

            return self::FAILURE;
        }

        try {
            $client = $clientFactory->make();
        } catch (InvalidArgumentException $exception) {
            $this->components->error($exception->getMessage());

            return self::FAILURE;
        }

        $this->components->info('Google Ads client initialized from .env credentials.');

        try {
            $accessibleCustomers = iterator_to_array(
                $client
                    ->getCustomerServiceClient()
                    ->listAccessibleCustomers(new ListAccessibleCustomersRequest)
                    ->getResourceNames(),
            );

            if ($accessibleCustomers === []) {
                $this->components->warn('OAuth works, but no accessible Google Ads customer accounts were returned.');
            } else {
                $this->components->info('Accessible Google Ads customer accounts:');

                foreach ($accessibleCustomers as $resourceName) {
                    $this->line("  - {$resourceName}");
                }
            }

            $customerId = $this->resolveCustomerId($clientFactory, $accessibleCustomers);

            if ($customerId === null) {
                $this->components->error('Could not determine a customer ID. Set GOOGLE_ADS_CUSTOMER_ID in .env using one of the accessible accounts above.');

                return self::FAILURE;
            }

            $this->newLine();
            $this->components->info("Testing Keyword Planner with customer ID {$customerId} and seed \"{$this->option('seed')}\".");

            $response = $client->getKeywordPlanIdeaServiceClient()->generateKeywordIdeas(
                new GenerateKeywordIdeasRequest([
                    'customer_id' => $customerId,
                    'language' => ResourceNames::forLanguageConstant((int) config('google-ads.language_id', 1000)),
                    'geo_target_constants' => array_map(
                        fn (int $geoTargetId): string => ResourceNames::forGeoTargetConstant($geoTargetId),
                        config('google-ads.geo_target_ids', [2840]),
                    ),
                    'keyword_plan_network' => KeywordPlanNetwork::GOOGLE_SEARCH,
                    'page_size' => max(1, (int) $this->option('limit')),
                    'keyword_seed' => new KeywordSeed([
                        'keywords' => [(string) $this->option('seed')],
                    ]),
                ]),
            );

            $printed = 0;

            foreach ($response->iterateAllElements() as $idea) {
                $metrics = $idea->getKeywordIdeaMetrics();
                $competition = KeywordCompetitionFormatter::label($metrics?->getCompetition());
                $avgMonthlySearches = $metrics?->getAvgMonthlySearches() ?? 0;

                $this->line(sprintf(
                    '  %d. %s | avg monthly searches: %s | competition: %s',
                    $printed + 1,
                    $idea->getText(),
                    number_format((int) $avgMonthlySearches),
                    $competition,
                ));

                $printed++;

                if ($printed >= (int) $this->option('limit')) {
                    break;
                }
            }

            if ($printed === 0) {
                $this->components->warn('Keyword Planner responded, but returned 0 ideas for that seed.');

                return self::FAILURE;
            }

            $this->newLine();
            $this->components->info('Google Ads Keyword Planner access verified successfully.');

            return self::SUCCESS;
        } catch (GoogleAdsException $exception) {
            $this->components->error('Google Ads API request failed.');

            foreach ($exception->getGoogleAdsFailure()?->getErrors() ?? [] as $error) {
                $this->line("  - {$error->getMessage()}");
            }

            return self::FAILURE;
        } catch (Throwable $exception) {
            $this->components->error($exception->getMessage());

            return self::FAILURE;
        }
    }

    /**
     * @param  list<string>  $accessibleCustomers
     */
    private function resolveCustomerId(GoogleAdsClientFactory $clientFactory, array $accessibleCustomers): ?string
    {
        $configured = $clientFactory->resolveCustomerId();

        if ($configured !== null) {
            return $configured;
        }

        $firstCustomer = $accessibleCustomers[0] ?? null;

        if (! is_string($firstCustomer) || ! preg_match('/customers\/(\d+)/', $firstCustomer, $matches)) {
            return null;
        }

        return $matches[1];
    }
}
