<?php

declare(strict_types=1);

namespace HyperfTest\Cases\Unit\Platform;

use App\Model\AggregateRefreshQueue;
use App\Platform\OrderConsumer;
use Carbon\Carbon;
use PHPUnit\Framework\TestCase;
use ReflectionMethod;

/**
 * @internal
 * @coversNothing
 */
class OrderConsumerEnqueueTest extends TestCase
{
    protected function runInCoroutine(callable $callback): void
    {
        if (\Swoole\Coroutine::getCid() > 0) {
            $callback();
            return;
        }

        $exception = null;
        \Swoole\Coroutine\run(static function () use ($callback, &$exception): void {
            try {
                $callback();
            } catch (\Throwable $e) {
                $exception = $e;
            }
        });
        if ($exception) {
            throw $exception;
        }
    }

    /**
     * 调用 protected enqueueAffectedDates 方法
     */
    protected function invokeEnqueue(array $payloads): void
    {
        $consumer = new OrderConsumer();
        $method = new ReflectionMethod($consumer, 'enqueueAffectedDates');
        $method->setAccessible(true);
        $method->invoke($consumer, $payloads);
    }

    /**
     * 清理指定日期的队列条目（前置 + 后置双保险）
     */
    protected function cleanupQueue(string $date): void
    {
        AggregateRefreshQueue::query()
            ->where('refresh_date', $date)
            ->where('aggregate_view', 'orders_daily_by_created')
            ->delete();
    }

    /**
     * 当日订单不应入队（在自动刷新策略覆盖窗口内）
     */
    public function test_today_payload_does_not_enqueue(): void
    {
        $this->runInCoroutine(function (): void {
            $today = Carbon::now()->toDateString();
            $payloads = [['created_date' => Carbon::now()->format('Y-m-d H:i:sP')]];

            $this->cleanupQueue($today);
            try {
                $this->invokeEnqueue($payloads);

                $row = AggregateRefreshQueue::query()
                    ->where('refresh_date', $today)
                    ->where('aggregate_view', 'orders_daily_by_created')
                    ->first();
                $this->assertNull($row);
            } finally {
                $this->cleanupQueue($today);
            }
        });
    }

    /**
     * 2 天前订单不应入队（仍在自动刷新策略 [now-3d, now-1h] 窗口内）
     */
    public function test_two_days_ago_payload_does_not_enqueue(): void
    {
        $this->runInCoroutine(function (): void {
            $two_days_ago = Carbon::now()->subDays(2)->toDateString();
            $payloads = [['created_date' => Carbon::now()->subDays(2)->format('Y-m-d H:i:sP')]];

            $this->cleanupQueue($two_days_ago);
            try {
                $this->invokeEnqueue($payloads);

                $row = AggregateRefreshQueue::query()
                    ->where('refresh_date', $two_days_ago)
                    ->where('aggregate_view', 'orders_daily_by_created')
                    ->first();
                $this->assertNull($row);
            } finally {
                $this->cleanupQueue($two_days_ago);
            }
        });
    }

    /**
     * 30 天前订单应入队 by_created（自动策略未覆盖，需补刷）
     */
    public function test_old_payload_enqueues_by_created(): void
    {
        $this->runInCoroutine(function (): void {
            $old_date = Carbon::now()->subDays(30)->toDateString();
            $payloads = [['created_date' => Carbon::now()->subDays(30)->format('Y-m-d H:i:sP')]];

            $this->cleanupQueue($old_date);
            try {
                $this->invokeEnqueue($payloads);

                $row = AggregateRefreshQueue::query()
                    ->where('refresh_date', $old_date)
                    ->where('aggregate_view', 'orders_daily_by_created')
                    ->first();
                $this->assertNotNull($row);
                $this->assertSame($old_date, $row->refresh_date);
                $this->assertSame('orders_daily_by_created', $row->aggregate_view);
            } finally {
                $this->cleanupQueue($old_date);
            }
        });
    }

    /**
     * 同日期重复入队由复合主键 + insertOrIgnore 防重
     */
    public function test_dedup_via_insert_or_ignore(): void
    {
        $this->runInCoroutine(function (): void {
            $old_date = Carbon::now()->subDays(45)->toDateString();
            $payloads = [
                ['created_date' => Carbon::now()->subDays(45)->format('Y-m-d H:i:sP')],
                ['created_date' => Carbon::now()->subDays(45)->format('Y-m-d H:i:sP')],
            ];

            $this->cleanupQueue($old_date);
            try {
                // 单批次内同日期 → $unique_dates map 去重
                $this->invokeEnqueue($payloads);
                // 跨批次同日期 → 复合主键 insertOrIgnore 防重
                $this->invokeEnqueue($payloads);

                $count = AggregateRefreshQueue::query()
                    ->where('refresh_date', $old_date)
                    ->where('aggregate_view', 'orders_daily_by_created')
                    ->count();
                $this->assertSame(1, $count);
            } finally {
                $this->cleanupQueue($old_date);
            }
        });
    }
}
