<?php

namespace Tests\Unit;

use App\Campaigns\Platforms\TikTokRules;
use App\Campaigns\TikTokCampaignFlow;
use Tests\TestCase;

class TikTokCampaignFlowTest extends TestCase
{
    public function test_shared_campaign_rules_expose_tiktok_objectives_and_budget(): void
    {
        $rules = app(TikTokRules::class);

        $this->assertSame(['SALES', 'LEAD_GENERATION', 'TRAFFIC', 'REACH'], $rules->objectives());
        $this->assertSame('SALES', $rules->objectiveFor('SALES'));
        $this->assertSame('LEAD_GENERATION', $rules->objectiveFor('LEADS'));
        $this->assertSame('adset:daily', $rules->budgetModes()[0]['value']);
        $this->assertTrue($rules->requiresPixel('SALES'));
        $this->assertFalse($rules->requiresPixel('TRAFFIC'));
    }

    public function test_campaign_flow_follows_advertiser_objective_type_destination_and_optimization_order(): void
    {
        $flow = app(TikTokCampaignFlow::class);

        $this->assertSame('advertiser_id', $flow->next([])['field']);
        $this->assertSame('objective', $flow->next(['advertiser_id' => 'advertiser-1'])['field']);
        $this->assertSame('campaign_type', $flow->next([
            'advertiser_id' => 'advertiser-1',
            'objective' => 'traffic',
        ])['field']);
        $this->assertSame('promotion_type', $flow->next([
            'advertiser_id' => 'advertiser-1',
            'objective' => 'traffic',
            'campaign_type' => 'manual',
        ])['field']);
        $this->assertSame('campaign_name', $flow->next([
            'advertiser_id' => 'advertiser-1',
            'objective' => 'traffic',
            'campaign_type' => 'manual',
            'promotion_type' => 'website',
        ])['field']);
        $this->assertSame('budget_type', $flow->next([
            'advertiser_id' => 'advertiser-1',
            'objective' => 'traffic',
            'campaign_name' => 'Traffic campaign',
            'campaign_type' => 'manual',
            'promotion_type' => 'website',
        ])['field']);
        $this->assertSame('campaign_budget_optimization', $flow->next([
            'advertiser_id' => 'advertiser-1',
            'objective' => 'traffic',
            'campaign_name' => 'Traffic campaign',
            'campaign_type' => 'manual',
            'promotion_type' => 'website',
            'budget_type' => 'daily',
        ])['field']);
        $this->assertCount(14, $flow->stages([]));
    }

    public function test_conversion_and_app_flows_require_only_applicable_measurement_fields(): void
    {
        $flow = app(TikTokCampaignFlow::class);
        $conversionDraft = ['objective' => 'sales', 'promotion_type' => 'website', 'optimization_goal' => 'conversion'];
        $appDraft = ['objective' => 'app_promotion', 'promotion_type' => 'app'];

        $this->assertSame(['optimization_location', 'optimization_goal', 'conversion_event', 'pixel_id', 'value_optimization'], array_column($flow->stages($conversionDraft)['optimization']['fields'], 'key'));
        $this->assertSame(['optimization_location', 'optimization_goal', 'app_event'], array_column($flow->stages($appDraft)['optimization']['fields'], 'key'));
        $this->assertNotContains('landing_page_url', array_column($flow->stages(['promotion_type' => 'app'])['ad_content']['fields'], 'key'));
        $this->assertContains('app_store_url', array_column($flow->stages(['promotion_type' => 'app'])['ad_content']['fields'], 'key'));
        $this->assertContains('deep_link_url', array_column($flow->stages(['promotion_type' => 'app'])['ad_content']['fields'], 'key'));
    }

    public function test_cbo_switches_budget_requirement_between_campaign_and_ad_group(): void
    {
        $flow = app(TikTokCampaignFlow::class);

        $this->assertSame(['campaign_name', 'budget_type', 'campaign_budget_optimization'], array_column($flow->stages([])['campaign_settings']['fields'], 'key'));
        $this->assertSame(['campaign_name', 'budget_type', 'campaign_budget_optimization', 'campaign_budget'], array_column($flow->stages(['campaign_budget_optimization' => 'on'])['campaign_settings']['fields'], 'key'));
        $this->assertContains('daily_budget', array_column($flow->stages(['campaign_budget_optimization' => 'off'])['ad_group']['fields'], 'key'));
        $this->assertNotContains('daily_budget', array_column($flow->stages(['campaign_budget_optimization' => 'on'])['ad_group']['fields'], 'key'));
    }

    public function test_preview_and_delivery_are_separate_final_checkpoints(): void
    {
        $flow = app(TikTokCampaignFlow::class);
        $draft = [
            'advertiser_id' => 'advertiser-1',
            'objective' => 'traffic',
            'campaign_name' => 'Traffic campaign',
            'campaign_type' => 'manual',
            'promotion_type' => 'website',
            'optimization_location' => 'website',
            'optimization_goal' => 'click',
            'budget_type' => 'daily',
            'campaign_budget_optimization' => 'off',
            'adgroup_name' => 'Traffic ad group',
            'placement' => 'tiktok',
            'targeting_mode' => 'automatic',
            'location_id' => 'US',
            'daily_budget' => '20',
            'schedule' => 'continuous',
            'bidding_strategy' => 'lowest_cost',
            'bid_cap' => '0',
            'adgroup_optimization_goal' => 'click',
            'identity_mode' => 'spark',
            'identity_id' => 'identity-1',
            'creative_source' => 'tiktok_post',
            'creative_format' => 'single_video',
            'tiktok_item_id' => 'post-1',
            'ad_text' => 'Visit our site',
            'call_to_action' => 'LEARN_MORE',
            'landing_page_url' => 'https://example.com',
            'tracking_enabled' => 'no',
            'display_name' => 'Brand',
            'profile_image_id' => 'profile-1',
            'delivery_settings' => 'standard',
            'validation_status' => 'passed',
            'created_campaign_id' => 'campaign-1',
            'created_adgroup_id' => 'adgroup-1',
            'created_ad_id' => 'ad-1',
            'api_status' => 'success',
        ];

        $draft['validation_status'] = 'passed';
        $this->assertNull($flow->next($draft));
    }

    /**
     * Reach and website lead generation can use a non-website destination;
     * website traffic, sales, and website lead generation require a URL.
     */
    public function test_supported_objectives_require_the_expected_landing_page_and_media_fields(): void
    {
        $flow = app(TikTokCampaignFlow::class);
        $objectives = [
            'reach' => ['destination' => 'tiktok_profile', 'landing_page' => false],
            'traffic' => ['destination' => 'website', 'landing_page' => true],
            'sales' => ['destination' => 'website', 'landing_page' => true],
            'lead_generation' => ['destination' => 'instant_form', 'landing_page' => false],
        ];

        foreach ($objectives as $objective => $configuration) {
            $adContentFields = array_column($flow->stages([
                'objective' => $objective,
                'promotion_type' => $configuration['destination'],
            ])['ad_content']['fields'], 'key');

            if ($configuration['landing_page']) {
                $this->assertContains('landing_page_url', $adContentFields, $objective);
            } else {
                $this->assertNotContains('landing_page_url', $adContentFields, $objective);
            }

            foreach (['upload_image', 'upload_video'] as $creativeSource) {
                $creativeFields = array_column($flow->stages([
                    'objective' => $objective,
                    'promotion_type' => $configuration['destination'],
                    'creative_source' => $creativeSource,
                ])['creative']['fields'], 'key');
                $this->assertContains('creative_format', $creativeFields, $objective.' '.$creativeSource);
                $this->assertContains('creative_asset_ids', $creativeFields, $objective.' '.$creativeSource);
            }
        }
    }
}
