<?php

namespace App\Mcp\Tools\GoogleAds;

use App\Agent\Choices;
use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Attributes\Description;
use Laravel\Mcp\Server\Tool;

#[Description('Show Google campaign setup choices as selectable radio options. Call without a choice to display options, or with a choice after the user selects one. For campaign_name, provide suggestion and alternative.')]
class OfferCampaignOptions extends Tool
{
    public function __construct(private readonly Choices $choices) {}

    public function schema(JsonSchema $schema): array
    {
        return [
            'field' => $schema->string()->description('The campaign draft field to offer choices for, such as campaign_name, daily_budget, ad_group_name, locations, or languages')->required(),
            'value' => $schema->string()->description('Selected option value; omit while offering options'),
            'suggestion' => $schema->string()->description('Suggested value for a dynamic field; omit for predefined enum fields'),
            'alternative' => $schema->string()->description('Second option for a dynamic field; omit for predefined enum fields'),
        ];
    }

    public function handle(Request $request): Response
    {
        $data = $request->validate([
            'field' => ['required', 'string', 'max:80'],
            'value' => ['nullable', 'string'],
            'suggestion' => ['nullable', 'string', 'max:255'],
            'alternative' => ['nullable', 'string', 'max:255'],
        ]);
        $selectedValue = $data['value'] ?? null;

        $presetFields = ['campaign_type', 'bidding_strategy', 'networks', 'devices', 'location_scope', 'positive_geo_target_type', 'negative_geo_target_type'];

        if (! in_array($data['field'], $presetFields, true) && filled($selectedValue)) {
            return Response::json(['ok' => true, 'field' => $data['field'], 'value' => $selectedValue]);
        }

        $options = match ($data['field']) {
            'daily_budget' => collect([
                $data['suggestion'] ?? null,
                $data['alternative'] ?? (($data['suggestion'] ?? 'Campaign').' alternative'),
            ])
                ->filter()
                ->unique()
                ->map(fn (string $budget): array => ['value' => $budget, 'label' => $budget])
                ->push(['value' => '__other__', 'label' => 'Other'])
                ->values()
                ->all(),
            'locations' => collect([
                $data['suggestion'] ?? null,
                $data['alternative'] ?? (($data['suggestion'] ?? 'Campaign').' alternative'),
            ])
                ->filter()
                ->unique()
                ->map(fn (string $location): array => ['value' => $location, 'label' => $location])
                ->push(['value' => '__other__', 'label' => 'Other'])
                ->values()
                ->all(),
            'languages' => collect([
                $data['suggestion'] ?? null,
                $data['alternative'] ?? (($data['suggestion'] ?? 'Campaign').' alternative'),
            ])
                ->filter()
                ->unique()
                ->map(fn (string $language): array => ['value' => $language, 'label' => $language])
                ->push(['value' => '__other__', 'label' => 'Other'])
                ->values()
                ->all(),
            'marketing_image_assets' => [
                ['value' => '__other__', 'label' => 'Other', 'hint' => 'Upload a landscape image directly to Google Ads'],
            ],
            'square_marketing_image_assets' => [
                ['value' => '__other__', 'label' => 'Other', 'hint' => 'Upload a square image directly to Google Ads'],
            ],
            'campaign_type' => [
                ['value' => 'Search', 'label' => 'Search', 'hint' => 'Search results and keywords'],
                ['value' => 'Display', 'label' => 'Display', 'hint' => 'Visual ads across Google Display Network'],
                ['value' => 'Performance Max', 'label' => 'Performance Max', 'hint' => 'Automated cross-channel campaign'],
                ['value' => 'Video', 'label' => 'Video', 'hint' => 'Video-led Performance Max with YouTube assets'],
            ],
            'bidding_strategy' => [
                ['value' => 'max_conversions', 'label' => 'Maximize conversions'],
                ['value' => 'max_conversion_value', 'label' => 'Maximize conversion value'],
                ['value' => 'max_clicks', 'label' => 'Maximize clicks'],
            ],
            'networks' => [
                ['value' => 'Google Search', 'label' => 'Google Search'],
                ['value' => 'Google Search and Search Partners', 'label' => 'Search + Search Partners'],
            ],
            'devices' => [
                ['value' => 'mobile,desktop,tablet', 'label' => 'All devices'],
                ['value' => 'mobile', 'label' => 'Mobile phones'],
                ['value' => 'desktop', 'label' => 'Computers / desktop'],
                ['value' => 'tablet', 'label' => 'Tablets'],
            ],
            'location_scope' => [
                ['value' => 'us', 'label' => 'United States'],
                ['value' => 'ca', 'label' => 'Canada'],
                ['value' => 'gb', 'label' => 'United Kingdom'],
                ['value' => 'other', 'label' => 'Other'],
            ],
            'positive_geo_target_type' => [
                ['value' => 'PRESENCE', 'label' => 'Presence', 'hint' => 'People in or regularly in included locations'],
                ['value' => 'PRESENCE_OR_INTEREST', 'label' => 'Presence or interest', 'hint' => 'People in, regularly in, or interested in locations'],
            ],
            'negative_geo_target_type' => [
                ['value' => 'PRESENCE', 'label' => 'Presence', 'hint' => 'Exclude people in or regularly in the location'],
            ],
            'logo_image_assets' => [
                ['value' => '__other__', 'label' => 'Upload logo', 'hint' => 'Upload a square logo image directly to Google Ads'],
            ],
            default => collect([
                $data['suggestion'] ?? null,
                $data['alternative'] ?? (($data['suggestion'] ?? 'Campaign').' alternative'),
            ])
                ->filter()
                ->unique()
                ->map(fn (string $name): array => ['value' => $name, 'label' => $name])
                ->values()
                ->all(),
        };

        if (blank($selectedValue)) {
            $choiceOptions = array_map(function (array $option): array {
                $value = (string) ($option['value'] ?? $option['label'] ?? '');

                return [
                    ...$option,
                    'value' => $value,
                    'label' => (string) ($option['label'] ?? $value),
                    'sends' => 'Set '.$this->fieldLabel($value).' to '.$value.'.',
                ];
            }, $options);
            $this->choices->offer(
                field: $data['field'],
                question: match ($data['field']) {
                    'campaign_name' => 'Choose a campaign name to continue.',
                    'campaign_type' => 'Which campaign type should we create?',
                    'bidding_strategy' => 'Which bidding strategy should we use?',
                    'networks' => 'Which Google networks should we target?',
                    'devices' => 'Which devices should we target?',
                    'location_scope' => 'Which location should this campaign target?',
                    'positive_geo_target_type' => 'How should included locations work?',
                    'negative_geo_target_type' => 'How should excluded locations work?',
                    'daily_budget' => 'What daily budget should we use?',
                    'locations' => 'Which locations should this campaign target?',
                    'languages' => 'Which languages should this campaign target?',
                    default => 'How should excluded locations work?',
                },
                options: $choiceOptions,
            );

            return Response::json(['ok' => true, 'field' => $data['field'], 'offered' => $options]);
        }

        if (! collect($options)->contains(fn (array $option): bool => ($option['value'] ?? null) === $selectedValue)) {
            return Response::error('Choose one of the options shown.');
        }

        return Response::json(['ok' => true, 'field' => $data['field'], 'value' => $selectedValue]);
    }

    private function fieldLabel(string $value): string
    {
        return str_replace('_', ' ', $value);
    }
}
