<?php

namespace App\Campaigns;

use App\Models\GoogleAdsCampaign;
use App\Services\GoogleAdsService;
use RuntimeException;

class GooglePerformanceProfileReader
{
    public function __construct(private readonly GoogleAdsService $googleAds) {}

    /**
     * @param  array{
     *     platform: string,
     *     external_campaign_id: string,
     *     local_campaign_id: ?int,
     *     local_google_ads_campaign_id: ?int
     * }  $candidate
     * @return array<string, mixed>
     */
    public function read(array $candidate): array
    {
        $local = $this->localCampaign($candidate);

        if ($local === null || $local->connection === null) {
            throw new RuntimeException('Local Google campaign row or connection is missing.');
        }

        try {
            $profile = $this->googleAds->readCampaignProfile($local->connection, (string) $local->google_campaign_id);
            $geo = $this->googleAds->readCampaignGeoTargets($local->connection, (string) $local->google_campaign_id);
        } catch (RuntimeException $exception) {
            return $this->fallback($local, $exception->getMessage());
        }

        $primaryStatus = strtoupper(trim((string) ($profile['primary_status'] ?? '')));
        $reasons = is_array($profile['primary_status_reasons'] ?? null)
            ? array_values(array_filter(array_map(
                fn (mixed $reason): string => trim((string) $reason),
                $profile['primary_status_reasons'],
            )))
            : [];
        [$deliveryStatus, $deliveryDetail] = $this->deliveryFrom($primaryStatus, $reasons);

        return [
            'name' => trim((string) ($profile['name'] ?? '')) ?: ($local->name),
            'objective' => trim((string) ($profile['advertising_channel_type'] ?? '')) ?: null,
            'daily_budget' => $profile['daily_budget'] ?? ($local->daily_budget !== null ? (float) $local->daily_budget : null),
            'currency' => null,
            'bid_strategy' => null,
            'platform_status' => trim((string) ($profile['status'] ?? '')) ?: null,
            'delivery_status' => $deliveryStatus,
            'delivery_detail' => $deliveryDetail,
            'regions' => $geo,
            'languages' => [],
            'platform_learning' => $this->learningFrom($primaryStatus, $reasons),
            'platform_payload' => [
                'campaign' => $profile,
            ],
            'account_id' => (string) ($local->connection->customer_id ?? ''),
            'started_at' => is_string($profile['start_date'] ?? null) ? $profile['start_date'] : null,
            'last_error' => null,
        ];
    }

    /**
     * @param  array{
     *     platform: string,
     *     local_google_ads_campaign_id: ?int
     * }  $candidate
     */
    private function localCampaign(array $candidate): ?GoogleAdsCampaign
    {
        if ($candidate['local_google_ads_campaign_id']) {
            return GoogleAdsCampaign::query()->with('connection')->find($candidate['local_google_ads_campaign_id']);
        }

        return GoogleAdsCampaign::query()
            ->with('connection')
            ->where('google_campaign_id', $candidate['external_campaign_id'])
            ->first();
    }

    /**
     * @param  list<string>  $reasons
     * @return array{0: ?string, 1: ?string}
     */
    private function deliveryFrom(string $primaryStatus, array $reasons): array
    {
        $detail = $reasons !== [] ? implode('; ', array_slice($reasons, 0, 3)) : null;

        if ($primaryStatus === '') {
            return [null, $detail];
        }

        if ($primaryStatus === 'LIMITED') {
            return ['LIMITED', $detail];
        }

        if ($primaryStatus === 'PENDING') {
            return ['PENDING', $detail];
        }

        if ($primaryStatus === 'NOT_ELIGIBLE') {
            return ['NOT_DELIVERING', $detail];
        }

        return [$primaryStatus, $detail];
    }

    /**
     * @param  list<string>  $reasons
     * @return array{source: string, status: ?string, detail: ?string}|null
     */
    private function learningFrom(string $primaryStatus, array $reasons): ?array
    {
        $joined = strtoupper(implode(' ', $reasons));

        if (str_contains($joined, 'LEARNING') || str_contains($joined, 'BIDDING')) {
            return [
                'source' => 'google_primary_status',
                'status' => 'LEARNING',
                'detail' => $joined !== '' ? implode('; ', array_slice($reasons, 0, 3)) : null,
            ];
        }

        if ($primaryStatus === 'PENDING') {
            return [
                'source' => 'google_primary_status',
                'status' => 'PENDING',
                'detail' => $joined !== '' ? implode('; ', array_slice($reasons, 0, 3)) : null,
            ];
        }

        return null;
    }

    /**
     * @return array<string, mixed>
     */
    private function fallback(GoogleAdsCampaign $local, string $message): array
    {
        return [
            'name' => $local->name,
            'objective' => null,
            'daily_budget' => $local->daily_budget !== null ? (float) $local->daily_budget : null,
            'currency' => null,
            'bid_strategy' => null,
            'platform_status' => $local->status,
            'delivery_status' => null,
            'delivery_detail' => null,
            'regions' => [],
            'languages' => [],
            'platform_learning' => null,
            'platform_payload' => null,
            'account_id' => (string) ($local->connection?->customer_id ?? ''),
            'started_at' => null,
            'last_error' => mb_substr($message, 0, 2000),
        ];
    }
}
