<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Process;
use Tests\TestCase;

/**
 * Swoole 队列监听器测试
 * 
 * 验证队列监听器在 Swoole 环境下的自动启动和运行
 */
class SwooleQueueListenerTest extends TestCase
{
    use RefreshDatabase;

    /**
     * 测试队列工作进程命令可用性
     * 
     * @test
     */
    public function test_queue_work_command_availability()
    {
        // 测试队列工作命令是否可用
        $exitCode = Artisan::call('queue:work', [
            '--help' => true,
        ]);

        $this->assertEquals(0, $exitCode, '队列工作命令不可用');
    }

    /**
     * 测试队列监听命令可用性
     * 
     * @test
     */
    public function test_queue_listen_command_availability()
    {
        // 测试队列监听命令是否可用
        $exitCode = Artisan::call('queue:listen', [
            '--help' => true,
        ]);

        $this->assertEquals(0, $exitCode, '队列监听命令不可用');
    }

    /**
     * 测试队列状态检查
     * 
     * @test
     */
    public function test_queue_status_check()
    {
        // 检查队列连接状态
        $defaultConnection = config('queue.default');
        $this->assertNotEmpty($defaultConnection, '默认队列连接未配置');

        // 检查队列配置
        $queueConfig = config("queue.connections.{$defaultConnection}");
        $this->assertIsArray($queueConfig, '队列连接配置无效');
        $this->assertArrayHasKey('driver', $queueConfig, '队列驱动未配置');
    }

    /**
     * 测试队列表是否存在（数据库队列）
     * 
     * @test
     */
    public function test_queue_tables_exist()
    {
        if (config('queue.default') === 'database') {
            // 检查 jobs 表是否存在
            $this->assertTrue(
                \Schema::hasTable('jobs'),
                '队列任务表不存在'
            );

            // 检查 failed_jobs 表是否存在
            $this->assertTrue(
                \Schema::hasTable('failed_jobs'),
                '失败任务表不存在'
            );
        }

        $this->assertTrue(true); // 如果不是数据库队列，测试通过
    }

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

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

    /**
     * 测试队列工作进程配置
     * 
     * @test
     */
    public function test_queue_worker_configuration()
    {
        // 检查 Octane 任务工作进程配置
        $taskWorkers = config('octane.task_workers', env('OCTANE_TASK_WORKERS'));
        $this->assertIsNumeric($taskWorkers, 'Octane 任务工作进程数量配置无效');
        $this->assertGreaterThan(0, $taskWorkers, 'Octane 任务工作进程数量必须大于 0');

        // 检查队列重试配置
        $retryAfter = config('queue.connections.database.retry_after');
        $this->assertIsNumeric($retryAfter, '队列重试时间配置无效');
        $this->assertGreaterThan(0, $retryAfter, '队列重试时间必须大于 0');
    }

    /**
     * 测试队列监听器进程管理
     * 
     * @test
     */
    public function test_queue_listener_process_management()
    {
        // 在测试环境中，我们只能验证命令的可用性
        // 实际的进程启动需要在集成测试中验证
        
        // 验证队列重启命令
        $exitCode = Artisan::call('queue:restart');
        $this->assertEquals(0, $exitCode, '队列重启命令执行失败');

        // 验证队列清理命令（可能在某些环境下不可用）
        try {
            $exitCode = Artisan::call('queue:clear');
            $this->assertEquals(0, $exitCode, '队列清理命令执行失败');
        } catch (\Exception $e) {
            // 如果命令不存在，跳过此测试
            $this->assertTrue(true, '队列清理命令在当前环境下不可用');
        }
    }

    /**
     * 测试队列任务超时配置
     * 
     * @test
     */
    public function test_queue_timeout_configuration()
    {
        // 检查文档转换任务的超时配置
        $conversionTimeout = config('documents.conversion.timeout', 300);
        $this->assertIsNumeric($conversionTimeout, '文档转换超时配置无效');
        $this->assertGreaterThan(0, $conversionTimeout, '文档转换超时时间必须大于 0');

        // 检查 Octane 最大执行时间配置
        $maxExecutionTime = config('octane.max_execution_time');
        $this->assertIsNumeric($maxExecutionTime, 'Octane 最大执行时间配置无效');
        
        // 如果设置了最大执行时间，应该大于队列任务超时时间
        if ($maxExecutionTime > 0) {
            // 对于测试环境，我们允许更灵活的配置
            // 在生产环境中，这个检查更重要
            if ($maxExecutionTime < $conversionTimeout) {
                $this->markTestSkipped(
                    "Octane 最大执行时间 ({$maxExecutionTime}s) 小于队列任务超时时间 ({$conversionTimeout}s)。" .
                    "在生产环境中应该调整此配置。"
                );
            } else {
                $this->assertGreaterThanOrEqual(
                    $conversionTimeout,
                    $maxExecutionTime,
                    'Octane 最大执行时间应该大于或等于队列任务超时时间'
                );
            }
        }
    }

    /**
     * 测试队列错误处理配置
     * 
     * @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, '队列重试延迟不能为负数');
    }
}