<?php

namespace App\Services\Keywords;

use App\Contracts\KeywordResearchService;
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 Illuminate\Support\Facades\Log;
use InvalidArgumentException;
use Throwable;

class GoogleAdsKeywordResearchService implements KeywordResearchService
{
    public function __construct(private GoogleAdsClientFactory $clientFactory) {}

    /**
     * @param  list<string>  $seedKeywords
     * @return list<array{
     *     term: string,
     *     avg_monthly_searches: int,
     *     competition: string,
     *     low_top_of_page_bid_micros?: int,
     * }>
     */
    public function ideasForSeeds(array $seedKeywords, string $geoTarget = 'US'): array
    {
        unset($geoTarget);

        $seeds = array_values(array_filter(array_map(
            static fn (mixed $seed): string => trim((string) $seed),
            $seedKeywords,
        )));

        if ($seeds === []) {
            return [];
        }

        if ($this->clientFactory->missingConfigurationKeys() !== []) {
            return [];
        }

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

        if ($customerId === null) {
            Log::warning('Google Ads keyword research skipped because no customer ID is configured.');

            return [];
        }

        try {
            $client = $this->clientFactory->make();
            $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) config('google-ads.max_keyword_ideas', 50)),
                    'keyword_seed' => new KeywordSeed([
                        'keywords' => $seeds,
                    ]),
                ]),
            );

            $ideas = [];
            $limit = max(1, (int) config('google-ads.max_keyword_ideas', 50));

            foreach ($response->iterateAllElements() as $result) {
                if (count($ideas) >= $limit) {
                    break;
                }
                $metrics = $result->getKeywordIdeaMetrics();
                $term = trim((string) $result->getText());

                if ($term === '') {
                    continue;
                }

                $idea = [
                    'term' => $term,
                    'avg_monthly_searches' => (int) ($metrics?->getAvgMonthlySearches() ?? 0),
                    'competition' => KeywordCompetitionFormatter::label($metrics?->getCompetition()),
                ];

                $lowBid = $metrics?->getLowTopOfPageBidMicros();

                if ($lowBid !== null && $lowBid > 0) {
                    $idea['low_top_of_page_bid_micros'] = (int) $lowBid;
                }

                $ideas[] = $idea;
            }

            Log::info('Google Ads keyword ideas fetched', [
                'seed_count' => count($seeds),
                'idea_count' => count($ideas),
            ]);

            return $ideas;
        } catch (GoogleAdsException|InvalidArgumentException|Throwable $exception) {
            Log::warning('Google Ads keyword research failed', [
                'seed_count' => count($seeds),
                'error' => $exception->getMessage(),
            ]);

            return [];
        }
    }
}
