<?php

namespace App\Agent;

use App\Mcp\Tools\GoogleAds\AnalyzeLandingPage;
use App\Mcp\Tools\TikTok\CreateTikTokAd;
use App\Mcp\Tools\TikTok\CreateTikTokPixel;
use App\Mcp\Tools\TikTok\FinalizeTikTokCampaign;
use App\Mcp\Tools\TikTok\ListAdvertisers;
use App\Mcp\Tools\TikTok\ListIdentities;
use App\Mcp\Tools\TikTok\ListTikTokPosts;
use App\Mcp\Tools\TikTok\OfferCampaignOptions;
use App\Mcp\Tools\TikTok\RetryTikTokAdGroup;
use App\Mcp\Tools\TikTok\SelectAdvertiser;
use App\Mcp\Tools\TikTok\SelectIdentity;
use App\Mcp\Tools\TikTok\SelectTikTokImageCreative;
use App\Mcp\Tools\TikTok\SelectTikTokVideoCreative;
use App\Mcp\Tools\TikTok\UpdateCampaignDraft;
use App\Mcp\Tools\TikTok\ValidateTikTokCampaignDraft;
use Illuminate\Http\Request;
use Laravel\Ai\Approvals\Decisions;
use Laravel\Ai\Concerns\RemembersConversations;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\HasTools;
use Laravel\Ai\Contracts\RemembersConversations as RemembersConversationsContract;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Enums\Lab;
use Laravel\Ai\Promptable;
use Laravel\Ai\Responses\AgentResponse;
use Laravel\Ai\Tools\McpServerTool;
use Stringable;

class TikTokAdsAgent implements Agent, HasTools, RemembersConversationsContract
{
    use Promptable {
        Promptable::prompt as protected runTurn;
    }
    use RemembersConversations;

    public function __construct(
        private readonly Request $request,
        private readonly Workspace $workspace,
    ) {
        $this->installResolver();
    }

    public function __clone(): void
    {
        $this->installResolver();
    }

    private function installResolver(): void
    {
        $this->workspace->resolveIdUsing(fn (): ?string => $this->currentConversation());
    }

    public function prompt(
        Decisions|string $prompt,
        array $attachments = [],
        Lab|array|string|null $provider = null,
        ?string $model = null,
        ?int $timeout = null,
    ): AgentResponse {
        return tap(
            $this->runTurn($prompt, $attachments, $provider, $model, $timeout),
            fn () => $this->workspace->id(),
        );
    }

    public function instructions(): Stringable|string
    {
        return <<<'INSTRUCTIONS'
You manage TikTok Ads planning through the available TikTok Ads MCP tools.

Build one persisted draft in this order and never ask a later-stage question early:
1. Select advertiser account.
2. Select campaign objective.
3. Select campaign type: Manual or Smart+. Offer Search Campaign only when the choices tool exposes it as supported.
4. Select destination / promotion type.
5. Select optimization location.
6. Select optimization goal.
7. For conversion goals, call offer-tiktok-campaign-options with field pixel_id. Auto-select one connected pixel or show clickable pixel options when multiple exist; never ask the user to type a Pixel ID. If the tool reports missing pixel_management permission, tell the user to reconnect using its provided URL and do not ask which pixel to choose. If no pixel exists after permission is granted, ask the user to approve a name and call create-tik-tok-pixel before continuing. Then collect the conversion event, app, or catalog details.
8. Select campaign budget optimization and campaign budget when CBO is on.
9. Configure ad-group placement, targeting, budget when CBO is off, schedule, bid strategy, and optimization.
10. Select identity mode and authorized TikTok identity.
11. Select creative source and format: library, upload video, upload image, carousel, or TikTok post.
12. Set ad text, CTA, and destination URL when applicable.
13. Configure or skip tracking.
14. Call validate-tiktok-campaign-draft and resolve every reported issue.
15. Immediately call create-tik-tok-ad after validation. It creates the campaign, ad group, and ad directly in PAUSED/DISABLE state.

After every confirmed or derived field, call update-tik-tok-campaign-draft with that exact field and value. Use offer-tik-tok-campaign-options for each finite choice, and never ask the user to type an option already shown. Complete the current stage before moving on. If a campaign field changes after validation, update it and call validate-tik-tok-campaign-draft again; never write validation_status manually. Once validation passes, immediately call create-tik-tok-ad. Do not ask for a separate preview, create/save mode, post-creation validation, or publish decision.

Use the selected campaign objective and destination throughout creation. Support Traffic, Sales, Lead Generation, and Reach when their required fields are available; do not silently replace the selected objective with Traffic. Use list-tik-tok-posts to auto-select one authorized TikTok post or show visual choices when several exist. Derive campaign/ad-group/ad names and ad text from landing-page analysis. The create-tik-tok-ad tool decides safe platform settings. Never ask the user for raw TikTok enums, location IDs, schedule timestamps, billing events, bid types, placement values, identity IDs, post IDs, or account-currency conversion.

Follow the staged flow above. Call list-identities for the selected advertiser. Call list-tik-tok-posts when Spark is selected. For Upload image, call select-tik-tok-image-creative and persist its returned image_id as the creative asset value before validation. For Upload video, call select-tik-tok-video-creative and persist its returned video_id in the draft before validation. Uploaded Single Image or Single Video with a CUSTOMIZED_USER identity may be created paused; do not route the active chat to local draft saving.

Landing page rule: it is optional for Reach, Video Views, Community Interaction, Branded Mission, and profile-based campaigns. It becomes required for Website Traffic, Website Sales, Website Lead Generation, and any website destination. App Promotion requires app store/deep-link details instead of a landing page. Instant Form, Messaging, TikTok Shop, and Search Campaign flows do not require a landing page unless the selected destination is Website. When a website destination is selected, call analyze_landing_page before asking for website copy or creative suggestions.

If TikTok is not connected, do not collect campaign fields. Tell the user to connect TikTok Ads first. After connection, list advertisers and after the user chooses one call select_advertiser with the selected advertiser_id. When advertiser choices are provided, let the user select with the visible options; do not ask them to type or repeat advertiser names. The configured advertiser may be suggested, but never claim it is authorized without a connected TikTok token.

Use landing-page analysis when a website destination is selected to suggest a concise campaign name and ad text. Validate the complete campaign configuration, then create the campaign, ad group, and ad directly in paused state.

For a validated manual website campaign, call create-tik-tok-ad with the selected objective, campaign_name, budget, landing_page_url, and ad_text. The tool uses the persisted authorized post, uploaded image, or uploaded video. If creation fails after a parent object is created, call retry-tik-tok-ad-group with existing_campaign_id and the saved objective and frequency_cap; if an ad group already exists, also pass existing_adgroup_id. Never create duplicate parent objects. After success, return campaign_id, adgroup_id, and ad_id and state that delivery is paused. If creation fails after a parent object is created, offer the visible retry choice and reuse the returned IDs.
INSTRUCTIONS;
    }

    /** @return list<Tool> */
    public function tools(): iterable
    {
        return [
            new McpServerTool(app(AnalyzeLandingPage::class)),
            new McpServerTool(app(CreateTikTokAd::class)),
            new McpServerTool(app(CreateTikTokPixel::class)),
            new McpServerTool(app(RetryTikTokAdGroup::class)),
            new McpServerTool(app(ListIdentities::class)),
            new McpServerTool(app(ListTikTokPosts::class)),
            new McpServerTool(app(OfferCampaignOptions::class)),
            new McpServerTool(app(ListAdvertisers::class)),
            new McpServerTool(app(SelectAdvertiser::class)),
            new McpServerTool(app(SelectIdentity::class)),
            new McpServerTool(app(SelectTikTokImageCreative::class)),
            new McpServerTool(app(SelectTikTokVideoCreative::class)),
            new McpServerTool(app(UpdateCampaignDraft::class)),
            new McpServerTool(app(ValidateTikTokCampaignDraft::class)),
            new McpServerTool(app(FinalizeTikTokCampaign::class)),
        ];
    }
}
