<?php

namespace Tests\Unit;

use App\Library\CampaignDecision\CampaignDecisionEngine;
use App\Library\CampaignDecision\CampaignDecisionVerdict;
use App\Library\CampaignDecision\CampaignPerformanceDataAssembler;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Tests\TestCase;

class RoiOnlyCampaignVerdictTest extends TestCase
{
    protected function setUp(): void
    {
        parent::setUp();

        Config::set([
            'campaign-performance.whale_enabled' => true,
            'campaign-decisions.defaults.learning_period_days' => 0,
            'campaign-decisions.defaults.max_test_spend' => 0,
            'database.connections.whale' => [
                'driver' => 'sqlite',
                'database' => ':memory:',
                'prefix' => '',
                'foreign_key_constraints' => false,
            ],
        ]);
        DB::purge('whale');

        $schema = Schema::connection('whale');
        $schema->create('arb_adops_campaign_performance', function (Blueprint $table): void {
            $table->date('date');
            $table->string('campaign_id');
            $table->unsignedInteger('clicks')->default(0);
            $table->decimal('sum_cpc', 12, 4)->default(0);
            $table->decimal('orders', 12, 4)->default(0);
            $table->decimal('net_revenue', 12, 4)->default(0);
        });
        $schema->create('roi_dashboard_campaign_stats', function (Blueprint $table): void {
            $table->date('date');
            $table->string('platform');
            $table->string('campaign_id');
            $table->decimal('spent', 12, 2)->default(0);
            $table->decimal('conversions', 12, 4)->default(0);
            $table->decimal('subscriptions', 12, 4)->default(0);
            $table->decimal('installs', 12, 4)->default(0);
            $table->decimal('bookings', 12, 4)->default(0);
            $table->decimal('leads', 12, 4)->default(0);
            $table->decimal('estimated_revenue', 12, 4)->default(0);
            $table->decimal('arb_orders', 12, 4)->default(0);
            $table->decimal('arb_sales_amount', 12, 4)->default(0);
        });
    }

    public function test_roi_spend_and_sales_decide_the_verdict_when_performance_rows_are_missing(): void
    {
        $this->travelTo('2026-09-22 12:00:00');
        $end = now()->copy()->startOfDay()->subDays(2);

        for ($i = 0; $i < 7; $i++) {
            DB::connection('whale')->table('roi_dashboard_campaign_stats')->insert([
                'date' => $end->copy()->subDays(6 - $i)->toDateString(),
                'platform' => 'Google',
                'campaign_id' => '23204583568',
                'spent' => 50,
                'conversions' => 1,
                'subscriptions' => 0,
                'installs' => 3,
                'bookings' => 0,
                'leads' => 1,
                'estimated_revenue' => 5,
                'arb_orders' => 0,
                'arb_sales_amount' => 200,
            ]);
        }

        $decision = $this->decide('23204583568', 'google');

        $this->assertSame(CampaignDecisionVerdict::ScaleUp->value, $decision['verdict']);
        $this->assertSame('roi_dashboard', $decision['channels']['outcome']['revenue_source']);
        $this->assertEquals(1400.0, $decision['channels']['outcome']['revenue']);
        $this->assertEquals(350.0, $decision['channels']['outcome']['spend']);
    }

    public function test_roi_spend_without_sales_pauses(): void
    {
        $this->travelTo('2026-09-22 12:00:00');

        DB::connection('whale')->table('roi_dashboard_campaign_stats')->insert([
            'date' => now()->copy()->subDays(2)->toDateString(),
            'platform' => 'google',
            'campaign_id' => '23204583568',
            'spent' => 40,
            'conversions' => 0,
            'subscriptions' => 0,
            'installs' => 0,
            'bookings' => 0,
            'leads' => 0,
            'estimated_revenue' => 99,
            'arb_orders' => 0,
            'arb_sales_amount' => 0,
        ]);

        $decision = $this->decide('23204583568', 'google');

        $this->assertSame(CampaignDecisionVerdict::Pause->value, $decision['verdict']);
        $this->assertEquals(0.0, $decision['channels']['outcome']['revenue']);
    }

    public function test_cost_per_conversion_of_two_dollars_maintains_when_sales_are_zero(): void
    {
        $this->insertRoiRow(spend: 100, conversions: 50);

        $decision = $this->decide('23204583568', 'google');

        $this->assertSame(CampaignDecisionVerdict::Maintain->value, $decision['verdict']);
        $this->assertSame('cost_per_conversions', $decision['reasons'][0]['metric']);
        $this->assertEquals(2.0, $decision['reasons'][0]['current']);
    }

    public function test_cost_per_conversion_of_four_dollars_watches_when_sales_are_zero(): void
    {
        $this->insertRoiRow(spend: 100, conversions: 25);

        $decision = $this->decide('23204583568', 'google');

        $this->assertSame(CampaignDecisionVerdict::Watch->value, $decision['verdict']);
        $this->assertEquals(4.0, $decision['reasons'][0]['current']);
    }

    public function test_cost_per_conversion_above_four_dollars_decreases_budget_when_sales_are_zero(): void
    {
        $this->insertRoiRow(spend: 100, conversions: 20);

        $decision = $this->decide('23204583568', 'google');

        $this->assertSame(CampaignDecisionVerdict::DecreaseBudget->value, $decision['verdict']);
        $this->assertSame('DECREASE_BUDGET', $decision['recommended_action']);
        $this->assertEquals(5.0, $decision['reasons'][0]['current']);
    }

    public function test_higher_result_count_wins_when_sales_are_zero(): void
    {
        $this->insertRoiRow(spend: 100, conversions: 10, subscriptions: 50, leads: 80);

        $decision = $this->decide('23204583568', 'google');

        $this->assertSame(CampaignDecisionVerdict::DecreaseBudget->value, $decision['verdict']);
        $this->assertSame('cost_per_conversions', $decision['reasons'][0]['metric']);
        $this->assertEquals(10.0, $decision['reasons'][0]['current']);
    }

    public function test_bookings_are_used_when_they_outnumber_installs_and_higher_counts_are_zero(): void
    {
        $this->insertRoiRow(spend: 100, installs: 10, bookings: 50);

        $decision = $this->decide('23204583568', 'google');

        $this->assertSame(CampaignDecisionVerdict::Maintain->value, $decision['verdict']);
        $this->assertSame('cost_per_bookings', $decision['reasons'][0]['metric']);
    }

    public function test_spend_below_the_minimum_does_not_use_the_count_ratio(): void
    {
        $this->insertRoiRow(spend: 20, conversions: 50);

        $decision = $this->decide('23204583568', 'google');

        $this->assertSame(CampaignDecisionVerdict::InsufficientData->value, $decision['verdict']);
    }

    public function test_performance_table_wins_when_both_have_rows(): void
    {
        $this->travelTo('2026-09-22 12:00:00');
        $date = now()->copy()->subDays(2)->toDateString();

        DB::connection('whale')->table('arb_adops_campaign_performance')->insert([
            'date' => $date,
            'campaign_id' => '1201',
            'clicks' => 4,
            'sum_cpc' => 1,
            'orders' => 2,
            'net_revenue' => 10,
        ]);
        DB::connection('whale')->table('roi_dashboard_campaign_stats')->insert([
            'date' => $date,
            'platform' => 'meta',
            'campaign_id' => '1201',
            'spent' => 50,
            'conversions' => 0,
            'subscriptions' => 0,
            'installs' => 0,
            'bookings' => 0,
            'leads' => 0,
            'estimated_revenue' => 0,
            'arb_orders' => 9,
            'arb_sales_amount' => 500,
        ]);

        $decision = $this->decide('1201', 'meta');

        $this->assertSame('affiliate', $decision['channels']['outcome']['revenue_source']);
        $this->assertEquals(10.0, $decision['channels']['outcome']['revenue']);
    }

    private function insertRoiRow(
        float $spend,
        float $conversions = 0,
        float $subscriptions = 0,
        float $installs = 0,
        float $bookings = 0,
        float $leads = 0,
        float $arbOrders = 0,
        float $sales = 0,
    ): void {
        $this->travelTo('2026-09-22 12:00:00');

        DB::connection('whale')->table('roi_dashboard_campaign_stats')->insert([
            'date' => now()->copy()->subDays(2)->toDateString(),
            'platform' => 'google',
            'campaign_id' => '23204583568',
            'spent' => $spend,
            'conversions' => $conversions,
            'subscriptions' => $subscriptions,
            'installs' => $installs,
            'bookings' => $bookings,
            'leads' => $leads,
            'estimated_revenue' => 0,
            'arb_orders' => $arbOrders,
            'arb_sales_amount' => $sales,
        ]);
    }

    /**
     * @return array<string, mixed>
     */
    private function decide(string $campaignId, string $platform): array
    {
        $context = app(CampaignPerformanceDataAssembler::class)->assemble([
            'platform' => $platform,
            'external_campaign_id' => $campaignId,
            'user_id' => 1,
            'account_id' => null,
            'name' => 'ROI campaign',
            'daily_budget' => null,
            'platform_status' => null,
            'delivery_status' => null,
            'started_at' => null,
            'sync_failed' => false,
            'sync_error' => null,
            'days' => collect(),
            'hours' => collect(),
        ], 'scheduled_hourly');

        return app(CampaignDecisionEngine::class)->evaluate($context);
    }
}
