<?php

namespace App\Agent\Tools\Campaign;

use App\Agent\Tools\Campaign\Concerns\ActsOnFocusedCampaign;
use App\Agent\Workspace;
use App\Campaigns\Objectives;
use App\Campaigns\Platforms\Platforms;
use App\Models\ArtifactFieldSource;
use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Tools\Request;
use Stringable;

/** Set the objective and landing page on the campaign in focus. */
class SetCampaignBasics implements Tool
{
    use ActsOnFocusedCampaign;

    public function __construct(private readonly Workspace $workspace) {}

    public function description(): Stringable|string
    {
        return 'Set the objective and/or landing page URL on the campaign in focus. '
            .'Objective must be one the platform supports: '.implode(', ', Objectives::SUPPORTED).'.';
    }

    public function schema(JsonSchema $schema): array
    {
        return [
            'objective' => $schema->string()
                ->description('One of '.implode(', ', Objectives::SUPPORTED).'.'),
            'landing_url' => $schema->string()
                ->description('The page the ad sends people to. Must be a full URL.'),
            'name' => $schema->string()->description('Rename the campaign.'),
            // Optional, and only meaningful on a platform that runs video.
            // Carried here rather than as its own step because a Performance
            // Max campaign runs perfectly well without one, it simply reaches
            // less inventory, and a step would make it look required.
            'youtube_video_id' => $schema->string()
                ->description('The eleven character YouTube video id to run as a video asset, '
                    .'for platforms that take one. Omit unless the user names a video.'),
        ];
    }

    public function handle(Request $request): Stringable|string
    {
        if (! $campaign = $this->focused()) {
            return $this->noCampaign();
        }

        $arguments = $request->all();
        $changed = [];

        if (filled($arguments['objective'] ?? null)) {
            $objective = strtoupper((string) $arguments['objective']);

            $rules = app(Platforms::class)->for($campaign);

            if (! in_array($objective, $rules->objectives(), true)) {
                return $this->json([
                    'ok' => false,
                    'error' => "[{$objective}] is not supported on {$rules->name()}.",
                    'supported' => $rules->objectives(),
                ]);
            }

            $campaign->objective = $objective;
            $campaign->optimization_goal = $rules->optimizationGoal($objective);
            $this->workspace->recordSource($campaign, 'objective', ArtifactFieldSource::USER_STATED);
            $changed['objective'] = $objective;
            $changed['optimization_goal'] = $campaign->optimization_goal;
        }

        if (filled($arguments['landing_url'] ?? null)) {
            $url = trim((string) $arguments['landing_url']);

            if (! filter_var($url, FILTER_VALIDATE_URL)) {
                return $this->json(['ok' => false, 'error' => "[{$url}] is not a valid URL."]);
            }

            $campaign->landing_url = $url;
            $this->workspace->recordSource($campaign, 'landing_url', ArtifactFieldSource::USER_STATED);
            $changed['landing_url'] = $url;
        }

        if (filled($arguments['name'] ?? null)) {
            $campaign->name = trim((string) $arguments['name']);
            $this->workspace->recordSource($campaign, 'name', ArtifactFieldSource::USER_STATED);
            $changed['name'] = $campaign->name;
        }

        if (filled($arguments['youtube_video_id'] ?? null)) {
            $video = trim((string) $arguments['youtube_video_id']);

            // The id, not a URL. Accepting a watch link and storing it whole
            // would reach Google as a video that does not exist, and Google
            // reports that as an unhelpful asset error long after the fact.
            if (preg_match('~(?:v=|youtu\.be/|/shorts/|/embed/)([A-Za-z0-9_-]{11})~', $video, $found)) {
                $video = $found[1];
            }

            if (! preg_match('/^[A-Za-z0-9_-]{11}$/', $video)) {
                return $this->json([
                    'ok' => false,
                    'error' => "[{$video}] is not a YouTube video id. It is eleven characters, "
                        .'and can be read off the watch URL.',
                ]);
            }

            $campaign->youtube_video_id = $video;
            $this->workspace->recordSource($campaign, 'youtube_video_id', ArtifactFieldSource::USER_STATED);
            $changed['youtube_video_id'] = $video;
        }

        if ($changed === []) {
            return $this->json(['ok' => false, 'error' => 'Nothing to set. Pass at least one field.']);
        }

        $campaign->save();

        return $this->json(['ok' => true, 'campaign_id' => $campaign->id, ...$changed]);
    }
}
