<?php

namespace App\Services\Meta;

/**
 * Everything an ad set needs, in one place, so the two transports build the
 * same request from the same source rather than drifting apart.
 */
readonly class AdSetSpec
{
    public function __construct(
        public string $adAccountId,
        public string $campaignId,
        public string $name,
        public int $dailyBudgetCents,
        public string $optimizationGoal,
        public array $targeting,
        public string $pageId,
        public ?string $pixelId = null,
        public ?string $conversionEvent = null,
        public string $bidStrategy = 'LOWEST_COST_WITHOUT_CAP',
        public ?int $bidAmountCents = null,
    ) {}

    /**
     * Meta's targeting spec.
     *
     * Naming a publisher platform switches off automatic placement, so the
     * positions within each platform have to be named too or the ad set is
     * rejected.
     */
    public function targetingSpec(): array
    {
        $spec = [
            'geo_locations' => ['countries' => array_values($this->targeting['countries'])],
            'age_min' => $this->targeting['age_min'] ?? 18,
            'age_max' => $this->targeting['age_max'] ?? 65,
            'targeting_automation' => ['advantage_audience' => 0],
        ];

        if (! empty($this->targeting['genders'])) {
            $spec['genders'] = array_values($this->targeting['genders']);   // 1 male, 2 female
        }

        if (! empty($this->targeting['devices'])) {
            $spec['device_platforms'] = array_values($this->targeting['devices']);
        }

        if (! empty($this->targeting['placements'])) {
            $spec['publisher_platforms'] = array_values($this->targeting['placements']);

            foreach ($this->targeting['placements'] as $platform) {
                if ($positions = self::POSITIONS[$platform] ?? null) {
                    $spec[$platform === 'audience_network' ? 'audience_network_positions' : "{$platform}_positions"] = $positions;
                }
            }
        }

        return $spec;
    }

    /** What the ad set optimises toward: a pixel event, or the page itself. */
    public function promotedObject(): array
    {
        return $this->pixelId && $this->conversionEvent
            ? ['pixel_id' => $this->pixelId, 'custom_event_type' => $this->conversionEvent]
            : ['page_id' => $this->pageId];
    }

    private const POSITIONS = [
        'facebook' => ['feed', 'video_feeds', 'story', 'facebook_reels', 'marketplace', 'search'],
        'instagram' => ['stream', 'story', 'reels', 'explore'],
        'messenger' => ['messenger_home', 'story'],
        'audience_network' => ['classic', 'rewarded_video'],
        'threads' => ['threads_feed'],
    ];
}
