<?php

namespace App\Mcp\Tools\TikTok;

use App\Agent\Choices;
use App\Models\TikTokConnection;
use App\Services\TikTokService;
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('Offer TikTok campaign objectives and setup choices as selectable options. Use this after landing-page analysis and before collecting campaign fields.')]
class OfferCampaignOptions extends Tool
{
    public function __construct(
        private readonly Choices $choices,
        private readonly TikTokService $tiktok,
    ) {}

    public function schema(JsonSchema $schema): array
    {
        return [
            'field' => $schema->string()->description('The planning field, such as campaign_objective or campaign_type')->required(),
            'value' => $schema->string()->description('Selected option value; omit while offering choices'),
            'objective' => $schema->string()->description('Selected objective used to filter dependent choices'),
            'suggestion' => $schema->string()->description('Suggested value for a dynamic field'),
            'alternative' => $schema->string()->description('First alternative for a dynamic field'),
            'alternative_2' => $schema->string()->description('Optional second alternative for a dynamic field'),
        ];
    }

    public function handle(Request $request): Response
    {
        $data = $request->validate([
            'field' => ['required', 'string', 'max:80'],
            'value' => ['nullable', 'string'],
            'objective' => ['nullable', 'string', 'max:80'],
            'suggestion' => ['nullable', 'string', 'max:255'],
            'alternative' => ['nullable', 'string', 'max:255'],
            'alternative_2' => ['nullable', 'string', 'max:255'],
        ]);
        $selectedValue = $data['value'] ?? null;
        $objective = strtolower((string) ($data['objective'] ?? ''));
        $searchSupported = config('services.tiktok.search_campaign_supported')
            && in_array(strtolower((string) ($data['objective'] ?? '')), ['traffic', 'sales'], true);

        if ($data['field'] === 'pixel_id' && blank($selectedValue)) {
            $pixelOptions = $this->pixelOptions($request);
            if (count($pixelOptions) === 1) {
                return Response::json([
                    'ok' => true,
                    'field' => 'pixel_id',
                    'value' => $pixelOptions[0]['value'],
                    'selected_pixel' => $pixelOptions[0],
                    'auto_selected' => true,
                ]);
            }
            if (count($pixelOptions) > 1) {
                $this->choices->offer(
                    field: 'pixel_id',
                    question: 'Which connected TikTok pixel tracks website purchases?',
                    options: $pixelOptions,
                );

                return Response::json(['ok' => true, 'field' => 'pixel_id', 'selection_required' => true]);
            }

            return Response::error('TikTok could not list conversion pixels because this OAuth token does not have pixel_management permission. Reconnect TikTok Ads here to grant the permission: '.route('tiktok.oauth.authorize'));
        }

        $options = match ($data['field']) {
            'campaign_objective' => [
                ['value' => 'reach', 'label' => 'Reach', 'hint' => 'Show the campaign to more people'],
                ['value' => 'traffic', 'label' => 'Traffic', 'hint' => 'Drive visits to your landing page'],
                ['value' => 'video_views', 'label' => 'Video views', 'hint' => 'Maximize qualified video views'],
                ['value' => 'community_interaction', 'label' => 'Community interaction', 'hint' => 'Drive profile, page, LIVE, or follow actions'],
                ['value' => 'branded_mission', 'label' => 'Branded mission', 'hint' => 'Configure a creator mission where available'],
                ['value' => 'app_promotion', 'label' => 'App promotion', 'hint' => 'Drive installs or app events'],
                ['value' => 'lead_generation', 'label' => 'Lead generation', 'hint' => 'Collect leads from interested customers'],
                ['value' => 'sales', 'label' => 'Sales', 'hint' => 'Drive conversions or purchases'],
            ],
            'campaign_type' => [
                ['value' => 'manual', 'label' => 'Manual', 'hint' => 'Configure campaign and ad group controls'],
                ['value' => 'smart_plus', 'label' => 'Smart+', 'hint' => 'Available as a local draft; remote support is not enabled'],
                ...($searchSupported ? [['value' => 'search_campaign', 'label' => 'Search campaign', 'hint' => 'Use search placement and keywords']] : []),
            ],
            'buying_type' => [
                ['value' => 'auction', 'label' => 'Auction'],
                ['value' => 'reach_frequency', 'label' => 'Reach and frequency', 'hint' => 'Available only for supported objectives/accounts'],
                ['value' => '__other__', 'label' => 'Other'],
            ],
            'budget_type' => [
                ['value' => 'daily', 'label' => 'Daily budget'],
                ['value' => 'lifetime', 'label' => 'Lifetime budget'],
                ['value' => '__other__', 'label' => 'Other'],
            ],
            'campaign_budget_optimization' => [
                ['value' => 'on', 'label' => 'CBO on', 'hint' => 'Set budget at campaign level'],
                ['value' => 'off', 'label' => 'CBO off', 'hint' => 'Set budget at ad-group level'],
            ],
            'destination', 'promotion_type' => $this->destinationsFor($objective),
            'optimization_location' => [
                ['value' => 'website', 'label' => 'Website'],
                ['value' => 'app', 'label' => 'App'],
                ['value' => 'instant_form', 'label' => 'Instant form'],
                ['value' => 'messaging', 'label' => 'Messaging'],
            ],
            'optimization_goal' => [
                ['value' => 'click', 'label' => 'Click'],
                ['value' => 'landing_page_view', 'label' => 'Landing page view'],
                ['value' => 'focused_view_6s', 'label' => '6-second focused view'],
                ['value' => 'focused_view_15s', 'label' => '15-second focused view'],
                ['value' => 'conversion', 'label' => 'Conversion'],
                ['value' => 'install', 'label' => 'Install'],
                ['value' => 'follow', 'label' => 'Follow'],
                ['value' => 'profile_visit', 'label' => 'Profile visit'],
                ['value' => '__other__', 'label' => 'Other'],
            ],
            'conversion_event' => [
                ['value' => 'Purchase', 'label' => 'Purchase', 'hint' => 'Track completed purchases'],
                ['value' => 'CompletePayment', 'label' => 'Complete payment', 'hint' => 'Track completed payments'],
                ['value' => 'AddToCart', 'label' => 'Add to cart', 'hint' => 'Track cart additions'],
                ['value' => 'ViewContent', 'label' => 'View content', 'hint' => 'Track content views'],
            ],
            'adgroup_optimization_goal' => [
                ['value' => 'click', 'label' => 'Click'],
                ['value' => 'landing_page_view', 'label' => 'Landing page view'],
                ['value' => 'conversion', 'label' => 'Conversion'],
                ['value' => 'install', 'label' => 'Install'],
                ['value' => 'follow', 'label' => 'Follow'],
                ['value' => 'profile_visit', 'label' => 'Profile visit'],
            ],
            'frequency_cap' => collect([1, 2, 3, 4, 5])->map(fn (int $value): array => [
                'value' => (string) $value,
                'label' => (string) $value.' impression'.($value === 1 ? '' : 's').' per day',
                'hint' => 'Limit the number of times one person sees the Reach ad each day.',
            ])->all(),
            'placement' => [
                ['value' => 'tiktok', 'label' => 'TikTok'],
            ],
            'gender' => [
                ['value' => 'all', 'label' => 'All genders'],
                ['value' => 'female', 'label' => 'Female'],
                ['value' => 'male', 'label' => 'Male'],
                ['value' => '__other__', 'label' => 'Other'],
            ],
            'targeting_mode' => [
                ['value' => 'manual', 'label' => 'Manual targeting'],
                ['value' => 'automatic', 'label' => 'Automatic targeting'],
                ['value' => 'expansion', 'label' => 'Targeting expansion'],
                ['value' => '__other__', 'label' => 'Other'],
            ],
            'tracking_enabled' => [
                ['value' => 'yes', 'label' => 'Set up tracking'],
                ['value' => 'no', 'label' => 'Skip tracking'],
            ],
            'identity' => [
                ['value' => 'spark', 'label' => 'Spark Ad'],
                ['value' => 'non_spark', 'label' => 'Non-Spark Ad'],
                ['value' => '__other__', 'label' => 'Other'],
            ],
            'identity_mode' => [
                ['value' => 'tiktok_account', 'label' => 'TikTok account'],
                ['value' => 'authorized_account', 'label' => 'Authorized account'],
                ['value' => 'spark', 'label' => 'Spark'],
                ['value' => 'non_spark', 'label' => 'Non-Spark'],
            ],
            'creative_source' => [
                ['value' => 'library', 'label' => 'Existing creative library', 'hint' => 'Save as a local draft'],
                ['value' => 'upload_video', 'label' => 'Upload video', 'hint' => 'Save as a local draft'],
                ['value' => 'upload_image', 'label' => 'Upload image', 'hint' => 'Save as a local draft'],
                ['value' => 'carousel', 'label' => 'Carousel', 'hint' => 'Save as a local draft'],
                ['value' => 'tiktok_post', 'label' => 'TikTok post', 'hint' => 'Supports paused remote Spark creation'],
            ],
            'creative_format' => [
                ['value' => 'single_video', 'label' => 'Single video'],
                ['value' => 'single_image', 'label' => 'Single image'],
                ['value' => 'carousel', 'label' => 'Carousel'],
            ],
            'schedule' => [
                ['value' => 'continuous', 'label' => 'Run continuously'],
                ['value' => 'scheduled', 'label' => 'Set start and end dates'],
            ],
            'delivery_settings' => [
                ['value' => 'standard', 'label' => 'Standard delivery'],
                ['value' => 'accelerated', 'label' => 'Accelerated delivery where supported'],
            ],
            'validation_status' => [
                ['value' => 'passed', 'label' => 'Validated'],
            ],
            'preview_confirmed' => [
                ['value' => 'yes', 'label' => 'Approve preview'],
                ['value' => 'no', 'label' => 'Keep editing'],
            ],
            'delivery_status' => [
                ['value' => 'draft', 'label' => 'Save as draft'],
                ['value' => 'paused', 'label' => 'Create paused on TikTok'],
            ],
            'create_confirmed' => [
                ['value' => 'yes', 'label' => 'Create as paused'],
                ['value' => 'no', 'label' => 'Edit campaign'],
            ],
            'creation_mode' => [
                ['value' => 'draft', 'label' => 'Save locally as draft'],
                ['value' => 'paused', 'label' => 'Create paused on TikTok'],
            ],
            'draft_confirmed' => [
                ['value' => 'yes', 'label' => 'Save local draft'],
            ],
            'publish_action' => [
                ['value' => 'publish', 'label' => 'Publish', 'hint' => 'Unavailable until TikTok publish API is configured'],
                ['value' => 'keep_paused', 'label' => 'Keep paused'],
                ['value' => 'edit', 'label' => 'Edit'],
            ],
            'daily_budget' => [
                ['value' => '20', 'label' => 'USD 20 per day'],
                ['value' => '50', 'label' => 'USD 50 per day'],
                ['value' => '100', 'label' => 'USD 100 per day'],
                ['value' => '__other__', 'label' => 'Other', 'hint' => 'Enter a different daily budget'],
            ],
            'campaign_budget' => [
                ['value' => '100', 'label' => 'USD 100 campaign budget'],
                ['value' => '500', 'label' => 'USD 500 campaign budget'],
                ['value' => '1000', 'label' => 'USD 1,000 campaign budget'],
                ['value' => '__other__', 'label' => 'Other', 'hint' => 'Enter a different campaign budget'],
            ],
            'call_to_action' => [
                ['value' => 'LEARN_MORE', 'label' => 'Learn more'],
                ['value' => 'SHOP_NOW', 'label' => 'Shop now'],
                ['value' => 'SIGN_UP', 'label' => 'Sign up'],
                ['value' => 'DOWNLOAD', 'label' => 'Download'],
                ['value' => 'CONTACT_US', 'label' => 'Contact us'],
            ],
            'country' => [
                ['value' => 'US', 'label' => 'United States'],
                ['value' => 'CA', 'label' => 'Canada'],
                ['value' => 'GB', 'label' => 'United Kingdom'],
                ['value' => '__other__', 'label' => 'Other', 'hint' => 'Choose another country'],
            ],
            'bidding_strategy' => [
                ['value' => 'lowest_cost', 'label' => 'Lowest cost', 'hint' => 'Maximize results within budget'],
                ['value' => 'cost_cap', 'label' => 'Cost cap', 'hint' => 'Control the average cost per result'],
                ['value' => 'bid_cap', 'label' => 'Bid cap', 'hint' => 'Set a maximum bid'],
                ['value' => '__other__', 'label' => 'Other'],
            ],
            default => collect([
                $data['suggestion'] ?? null,
                $data['alternative'] ?? null,
                $data['alternative_2'] ?? null,
            ])
                ->filter(fn (?string $value): bool => filled($value))
                ->unique()
                ->map(fn (string $value): array => ['value' => $value, 'label' => $value])
                ->push(['value' => '__other__', 'label' => 'Other', 'hint' => 'Enter a different value'])
                ->values()
                ->all(),
        };

        if ($options === []) {
            return Response::error('TikTok does not support choices for this planning field yet.');
        }

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

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

        $this->choices->offer(
            field: $data['field'],
            question: match ($data['field']) {
                'campaign_objective' => 'What is the main goal for this TikTok campaign?',
                'campaign_type' => 'Which TikTok campaign format should we plan?',
                'promotion_type' => 'Where should the campaign send people?',
                'identity_mode' => 'Which identity format should we use?',
                'creative_source' => 'Where should we get the ad creative?',
                'creative_format' => 'Which creative format should we use?',
                'campaign_budget_optimization' => 'Should campaign budget optimization be on or off?',
                'tracking_enabled' => 'Do you want to configure tracking?',
                'preview_confirmed' => 'Does this complete campaign preview look right?',
                'delivery_status' => 'How should this campaign be saved?',
                'daily_budget' => 'What daily budget should we use?',
                'country' => 'Which country should this TikTok campaign target?',
                'bidding_strategy' => 'Which bidding strategy should we use?',
                'creative_source' => 'Where should we get the campaign creative?',
                'destination' => 'Where should the campaign send people?',
                'optimization_location' => 'Where should TikTok optimize delivery?',
                'optimization_goal' => 'What result should TikTok optimize for?',
                'placement' => 'Where should the ads appear?',
                'delivery_settings' => 'Which delivery setting should we use?',
                'identity' => 'Which ad identity should we use?',
                default => 'Choose a TikTok campaign value.',
            },
            options: array_map(fn (array $option): array => [
                ...$option,
                'sends' => 'Use TikTok '.$option['label'].'.',
            ], $options),
        );

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

    /** @return list<array{value: string, label: string, hint: string, sends: string}> */
    private function pixelOptions(Request $request): array
    {
        if (filled(config('services.tiktok.pixel_id'))) {
            return [[
                'value' => (string) config('services.tiktok.pixel_id'),
                'label' => (string) config('services.tiktok.pixel_name').' ('.config('services.tiktok.pixel_id').')',
                'hint' => 'Configured TikTok pixel',
                'sends' => 'Use TikTok pixel '.config('services.tiktok.pixel_id').'.',
            ]];
        }

        $connection = TikTokConnection::query()->where('user_id', $request->user()?->getAuthIdentifier())->first();
        if ($connection === null || blank($connection->access_token) || blank($connection->advertiser_id)) {
            return [];
        }

        try {
            $pixels = $this->tiktok->pixels($connection);
        } catch (\Throwable $exception) {
            report($exception);

            return [];
        }

        return array_map(fn (array $pixel): array => [
            'value' => $pixel['pixel_id'],
            'label' => $pixel['pixel_name'].' ('.$pixel['pixel_id'].')',
            'hint' => 'Connected TikTok pixel',
            'sends' => 'Use TikTok pixel '.$pixel['pixel_id'].'.',
        ], $pixels);
    }

    /** @return list<array{value: string, label: string, hint: string}> */
    private function destinationsFor(string $objective): array
    {
        $supported = match ($objective) {
            'app_promotion' => ['app'],
            'video_views', 'branded_mission' => ['tiktok_profile'],
            'community_interaction' => ['tiktok_profile', 'messaging'],
            'lead_generation' => ['instant_form', 'messaging', 'website'],
            'sales' => ['website', 'app', 'tiktok_shop'],
            default => ['website', 'app', 'tiktok_profile', 'messaging'],
        };

        return collect([
            'website' => ['Website', 'Requires a destination URL'],
            'app' => ['App', 'Requires app-store and deep-link details'],
            'tiktok_shop' => ['TikTok Shop', 'Requires a supported shop/catalog'],
            'tiktok_profile' => ['TikTok Profile', 'Profile destination'],
            'instant_form' => ['Instant Form', 'Requires an authorized lead form'],
            'messaging' => ['Messaging', 'Requires a supported messaging account'],
        ])->only($supported)->map(fn (array $details, string $value): array => [
            'value' => $value,
            'label' => $details[0],
            'hint' => $details[1],
        ])->values()->all();
    }
}
