<?php

namespace Tests\Feature;

use App\Jobs\ConvertDocumentToMarkdown;
use App\Models\Document;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Queue;
use Tests\TestCase;

/**
 * 队列系统验证测试
 * 
 * 验证队列系统在 Swoole 环境下的基本功能
 */
class QueueSystemValidationTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();
        
        // 禁用搜索功能以避免 Meilisearch 连接问题
        config(['scout.driver' => 'null']);
    }

    /**
     * 测试队列系统基本功能
     * 
     * @test
     */
    public function test_queue_system_basic_functionality()
    {
        // 验证队列配置
        $this->assertNotEmpty(config('queue.default'), '队列默认连接未配置');
        
        // 验证队列连接配置
        $defaultConnection = config('queue.default');
        $connectionConfig = config("queue.connections.{$defaultConnection}");
        $this->assertIsArray($connectionConfig, '队列连接配置无效');
        $this->assertArrayHasKey('driver', $connectionConfig, '队列驱动未配置');
        
        // 验证队列命令可用性
        $exitCode = Artisan::call('queue:work', ['--help' => true]);
        $this->assertEquals(0, $exitCode, '队列工作命令不可用');
    }

    /**
     * 测试文档转换任务的基本功能
     * 
     * @test
     */
    public function test_document_conversion_job_basic_functionality()
    {
        // 创建测试数据
        $user = User::factory()->create();
        $document = Document::factory()->create([
            'uploaded_by' => $user->id,
            'title' => '验证测试文档',
        ]);

        // 使用模拟队列
        Queue::fake();

        // 分发任务
        ConvertDocumentToMarkdown::dispatch($document);

        // 验证任务已分发
        Queue::assertPushed(ConvertDocumentToMarkdown::class);

        // 验证任务配置
        $job = new ConvertDocumentToMarkdown($document);
        $this->assertIsNumeric($job->tries, '任务重试次数配置无效');
        $this->assertIsNumeric($job->timeout, '任务超时配置无效');
        $this->assertIsNumeric($job->backoff, '任务重试延迟配置无效');
    }

    /**
     * 测试 Swoole 与队列的兼容性配置
     * 
     * @test
     */
    public function test_swoole_queue_compatibility_configuration()
    {
        // 验证 Octane 配置
        $octaneServer = config('octane.server');
        $this->assertEquals('swoole', $octaneServer, 'Octane 服务器未配置为 Swoole');

        // 验证 Octane 任务工作进程配置
        $taskWorkers = config('octane.task_workers', env('OCTANE_TASK_WORKERS'));
        $this->assertIsNumeric($taskWorkers, 'Octane 任务工作进程数量配置无效');
        $this->assertGreaterThan(0, $taskWorkers, 'Octane 任务工作进程数量必须大于 0');

        // 验证队列与 Swoole 的兼容性
        $queueConnection = config('queue.default');
        $queueDriver = config("queue.connections.{$queueConnection}.driver");
        $supportedDrivers = ['database', 'redis', 'sync'];
        
        $this->assertContains(
            $queueDriver,
            $supportedDrivers,
            "队列驱动 {$queueDriver} 可能与 Swoole 不兼容"
        );
    }

    /**
     * 测试队列任务的内存管理
     * 
     * @test
     */
    public function test_queue_memory_management()
    {
        $initialMemory = memory_get_usage();

        // 创建多个任务实例
        $user = User::factory()->create();
        $jobs = [];
        
        for ($i = 0; $i < 10; $i++) {
            $document = Document::factory()->create(['uploaded_by' => $user->id]);
            $jobs[] = new ConvertDocumentToMarkdown($document);
        }

        // 清理任务实例
        unset($jobs);
        gc_collect_cycles();

        $finalMemory = memory_get_usage();
        $memoryIncrease = $finalMemory - $initialMemory;

        // 验证内存使用合理
        $this->assertLessThan(5 * 1024 * 1024, $memoryIncrease, '队列任务内存使用过多');
    }

    /**
     * 测试队列错误处理配置
     * 
     * @test
     */
    public function test_queue_error_handling_configuration()
    {
        // 验证失败队列配置
        $failedDriver = config('queue.failed.driver');
        $this->assertNotEmpty($failedDriver, '失败队列驱动未配置');

        // 验证文档转换相关配置
        $retryTimes = config('documents.conversion.retry_times', 3);
        $this->assertIsNumeric($retryTimes, '队列重试次数配置无效');
        $this->assertGreaterThan(0, $retryTimes, '队列重试次数必须大于 0');

        $retryDelay = config('documents.conversion.retry_delay', 60);
        $this->assertIsNumeric($retryDelay, '队列重试延迟配置无效');
        $this->assertGreaterThanOrEqual(0, $retryDelay, '队列重试延迟不能为负数');

        $timeout = config('documents.conversion.timeout', 300);
        $this->assertIsNumeric($timeout, '队列任务超时配置无效');
        $this->assertGreaterThan(0, $timeout, '队列任务超时时间必须大于 0');
    }

    /**
     * 测试队列系统的整体健康状态
     * 
     * @test
     */
    public function test_queue_system_health()
    {
        // 验证数据库表存在（如果使用数据库队列）
        if (config('queue.default') === 'database') {
            $this->assertTrue(\Schema::hasTable('jobs'), '队列任务表不存在');
            $this->assertTrue(\Schema::hasTable('failed_jobs'), '失败任务表不存在');
        }

        // 验证队列重启命令
        $exitCode = Artisan::call('queue:restart');
        $this->assertEquals(0, $exitCode, '队列重启命令执行失败');

        // 验证基本的队列操作
        Queue::fake();
        
        $user = User::factory()->create();
        $document = Document::factory()->create(['uploaded_by' => $user->id]);
        
        // 测试任务分发
        ConvertDocumentToMarkdown::dispatch($document);
        Queue::assertPushed(ConvertDocumentToMarkdown::class);

        // 测试任务序列化
        $job = new ConvertDocumentToMarkdown($document);
        $serialized = serialize($job);
        $unserialized = unserialize($serialized);
        $this->assertInstanceOf(ConvertDocumentToMarkdown::class, $unserialized);
    }
}