<?php

namespace App\Agent\Tools\Campaign;

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

/**
 * Confirm an ad account exists, is usable, and is one we are allowed to touch.
 *
 * Must succeed before Pages, pixels or uploads: all three are account scoped.
 * Changing the account clears them, because a Page id from one account is
 * meaningless on another and silently keeping it is how an ad ends up posted
 * by the wrong brand.
 */
class VerifyAdAccount implements Tool
{
    use ActsOnFocusedCampaign;

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

    public function description(): Stringable|string
    {
        return 'Verify an ad account by id and attach it to the campaign in focus. '
            .'Call this directly when the user names an account; only list accounts when they have not.';
    }

    public function schema(JsonSchema $schema): array
    {
        return [
            'ad_account_id' => $schema->string()
                ->description('The ad account id, with or without the act_ prefix.')
                ->required(),
        ];
    }

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

        if ($campaign->platform !== 'meta') {
            return $this->json([
                'ok' => false,
                'error' => sprintf(
                    '%s is not connected yet, so an ad account cannot be verified for it.',
                    app(Platforms::class)->for($campaign)->name(),
                ),
            ]);
        }

        $id = trim((string) ($request->all()['ad_account_id'] ?? ''));
        $id = str_starts_with($id, 'act_') ? $id : 'act_'.ltrim($id, '_');

        try {
            $account = $this->meta->on($campaign->id, 'agent')->adAccount($id);
        } catch (MetaException $e) {
            return $this->json(['ok' => false, 'error' => $e->getMessage()]);
        }

        if ((int) ($account['account_status'] ?? 0) !== 1) {
            return $this->json([
                'ok' => false,
                'error' => "Ad account {$id} is not active (status {$account['account_status']}).",
            ]);
        }

        $changed = $campaign->ad_account_id && $campaign->ad_account_id !== $account['id'];

        $campaign->update([
            'ad_account_id' => $account['id'],
            'currency' => $account['currency'] ?? $campaign->currency,
            // Account scoped, so they cannot survive a change of account.
            ...$changed ? ['page_id' => null, 'pixel_id' => null] : [],
        ]);

        $this->workspace->recordSource($campaign, 'ad_account_id', ArtifactFieldSource::PLATFORM_RETURNED);

        if ($changed) {
            $this->workspace->forgetSources($campaign, 'page_id', 'pixel_id');
        }

        return $this->json(array_filter([
            'ok' => true,
            'ad_account_id' => $account['id'],
            'name' => $account['name'] ?? null,
            'currency' => $account['currency'] ?? null,
            'cleared_because_account_changed' => $changed ? ['page_id', 'pixel_id'] : null,
        ], fn ($v) => $v !== null));
    }
}
