<?php

declare(strict_types=1);

namespace HyperfTest\Cases\Integration\Materialization;

use Hyperf\DbConnection\Db;
use PHPUnit\Framework\TestCase;

/**
 * P22.3 物化对象集成测试：跨两类物化对象 + 跨命名空间索引的存在性断言。
 *
 * 与 P22.2 烟雾测试 `System/MaterializedViewSmokeTest` 各自关注点不同：
 * - 烟雾测试：单点测试，专测 by_paid 视图与索引
 * - 本测试：跨两类对象（连续聚合 + PG 物化视图）+ 跨命名空间索引（pg_indexes 不区分视图类型）
 *
 * @internal
 * @coversNothing
 */
class MaterializationObjectsTest extends TestCase
{
    /**
     * @template T
     * @param callable(): T $callback
     * @return T
     */
    protected function runInCoroutine(callable $callback): mixed
    {
        if (\Swoole\Coroutine::getCid() > 0) {
            return $callback();
        }

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

    public function test_continuous_aggregate_exists(): void
    {
        $rows = $this->runInCoroutine(static fn () => Db::select(
            "SELECT view_name FROM timescaledb_information.continuous_aggregates
             WHERE view_name = 'orders_daily_by_created'"
        ));
        $this->assertCount(1, $rows);
    }

    public function test_pg_materialized_view_exists(): void
    {
        $rows = $this->runInCoroutine(static fn () => Db::select(
            "SELECT matviewname FROM pg_matviews
             WHERE matviewname = 'orders_daily_by_paid'"
        ));
        $this->assertCount(1, $rows);
    }

    public function test_refresh_policy_registered(): void
    {
        // 显式过滤 hypertable_name，避免未来追加其他连续聚合策略时此断言无关地失败。
        $rows = $this->runInCoroutine(static fn () => Db::select(
            "SELECT hypertable_name FROM timescaledb_information.jobs
             WHERE proc_name = 'policy_refresh_continuous_aggregate'
               AND hypertable_name = 'orders_daily_by_created'"
        ));
        $this->assertCount(1, $rows);
    }

    public function test_by_created_indexes_present(): void
    {
        // P22.1 创建 5 复合索引；chunk 索引名是 `_hyper_*` 不会被 LIKE 'idx_*' 匹配。
        $rows = $this->runInCoroutine(static fn () => Db::select(
            "SELECT indexname FROM pg_indexes WHERE indexname LIKE 'idx_orders_daily_by_created%'"
        ));
        $this->assertCount(5, $rows);
    }

    public function test_by_paid_indexes_present(): void
    {
        // P22.2 创建 1 UNIQUE + 5 复合 = 6 索引。
        $rows = $this->runInCoroutine(static fn () => Db::select(
            "SELECT indexname FROM pg_indexes WHERE indexname LIKE 'idx_orders_daily_by_paid%'"
        ));
        $this->assertCount(6, $rows);
    }
}
