<?php

namespace App\Campaigns\Targeting;

use App\Models\Location;
use App\Models\PlatformLocation;
use RuntimeException;

class CountryCatalog
{
    public function __construct(private readonly CountryLookup $lookup) {}

    /** @return array<string, string> */
    public function names(): array
    {
        $stored = Location::query()->where('type', 'country')->pluck('name', 'iso_code')->all();

        return array_replace((array) config('countries'), $stored);
    }

    /** @return array<string, string> country code => verified external ID */
    public function verified(string $platform): array
    {
        return PlatformLocation::query()
            ->where('platform', $platform)
            ->where('status', 'verified')
            ->whereNotNull('verified_at')
            ->where('verified_at', '>=', now()->subDays(30))
            ->whereHas('location', fn ($query) => $query->where('type', 'country'))
            ->with('location:id,iso_code')
            ->get()
            ->mapWithKeys(fn (PlatformLocation $mapping): array => [$mapping->location->iso_code => $mapping->external_id])
            ->all();
    }

    /**
     * Resolve country IDs before the first remote mutation. Never substitute a
     * different region or omit a country when a provider returns no exact match.
     *
     * @param  list<string>  $codes
     * @return list<string>
     */
    public function resolve(string $platform, array $codes, ?string $adAccountId = null): array
    {
        if ($codes === []) {
            throw new RuntimeException('Choose at least one country before publishing.');
        }

        $names = $this->names();
        $verified = $this->verified($platform);
        $ids = [];

        foreach ($codes as $given) {
            $code = strtoupper(trim($given));
            if (! preg_match('/^[A-Z]{2}$/', $code) || ! isset($names[$code])) {
                throw new RuntimeException('Unrecognised country code: '.$given.'.');
            }

            if (! isset($verified[$code])) {
                $found = $this->lookup->find($platform, $code, $names[$code], $adAccountId);
                if ($found === null) {
                    throw new RuntimeException(ucfirst($platform).' country mapping is not available for: '.$code.'. No campaign was created.');
                }

                $location = Location::query()->firstOrCreate(
                    ['iso_code' => $code],
                    ['type' => 'country', 'name' => $names[$code], 'country_code' => $code, 'source' => 'iso_3166_1', 'source_key' => $code],
                );

                PlatformLocation::query()->updateOrCreate(
                    ['platform' => $platform, 'location_id' => $location->id],
                    ['external_id' => $found['id'], 'provider_name' => $found['name'], 'status' => 'verified', 'verified_at' => now()],
                );
                $verified[$code] = $found['id'];
            }

            $ids[] = $verified[$code];
        }

        return array_values(array_unique($ids));
    }
}
