/**
 * 属性测试：Tab 切换与 URL 查询参数同步 round-trip
 *
 * Feature: admin-web-restructure, Property 8: Tab 切换与 URL 查询参数同步 round-trip
 * **Validates: Requirements 10.4**
 *
 * 对于任意 Tab 视图页面，设置 URL 查询参数 `?tab=X` 后渲染页面，
 * 当前激活的 Tab 应为 X；点击 Tab Y 后，URL 查询参数应更新为 `?tab=Y`。
 *
 * 当前仅测试 ETLTasks（TriggerManager 待后续任务创建后扩展）。
 */

import React from "react";
import { describe, it, expect, vi, afterEach } from "vitest";
import { render, fireEvent, cleanup } from "@testing-library/react";
import { MemoryRouter, useLocation } from "react-router-dom";
import * as fc from "fast-check";

/* ------------------------------------------------------------------ */
/*  Mock 子组件，避免内部 API 调用                                      */
/* ------------------------------------------------------------------ */

vi.mock("../pages/TaskConfig", () => ({
  default: () => <div data-testid="tab-content-config">TaskConfig</div>,
}));
vi.mock("../pages/TaskManager", () => ({
  QueueTab: () => <div data-testid="tab-content-queue">QueueTab</div>,
  HistoryTab: () => <div data-testid="tab-content-history">HistoryTab</div>,
}));
vi.mock("../components/ScheduleTab", () => ({
  default: () => <div data-testid="tab-content-schedule">ScheduleTab</div>,
}));
vi.mock("../pages/ETLStatus", () => ({
  default: () => <div data-testid="tab-content-status">ETLStatus</div>,
}));

import ETLTasks from "../pages/ETLTasks";

/* ------------------------------------------------------------------ */
/*  辅助：捕获当前 URL search 参数                                      */
/* ------------------------------------------------------------------ */

function LocationSpy({ onLocation }: { onLocation: (s: string) => void }) {
  const location = useLocation();
  React.useEffect(() => {
    onLocation(location.search);
  });
  return null;
}

/* ------------------------------------------------------------------ */
/*  页面配置（可扩展 TriggerManager）                                   */
/* ------------------------------------------------------------------ */

interface TabPageConfig {
  name: string;
  validTabs: readonly string[];
  defaultTab: string;
  Component: React.FC;
  basePath: string;
  /** Tab label 文本中包含的关键字，用于定位 Tab 元素 */
  tabLabels: Record<string, string>;
}

const ETL_TASKS_CONFIG: TabPageConfig = {
  name: "ETLTasks",
  validTabs: ["config", "queue", "schedule", "history", "status"],
  defaultTab: "config",
  Component: ETLTasks,
  basePath: "/etl-tasks",
  tabLabels: {
    config: "发起",
    queue: "队列",
    schedule: "调度",
    history: "历史",
    status: "状态",
  },
};

// TriggerManager 配置占位，待 task 10.1 创建后启用
// const TRIGGER_MANAGER_CONFIG: TabPageConfig = { ... };

const PAGE_CONFIGS: TabPageConfig[] = [ETL_TASKS_CONFIG];

/* ------------------------------------------------------------------ */
/*  每次测试后清理 DOM                                                  */
/* ------------------------------------------------------------------ */

afterEach(() => {
  cleanup();
});

/* ------------------------------------------------------------------ */
/*  属性测试                                                           */
/* ------------------------------------------------------------------ */

// DOM 渲染属性测试：numRuns=20 覆盖所有 tab 值多次，避免 jsdom 超时
const PBT_NUM_RUNS = 20;
// 给 DOM 属性测试更长的超时（30s）
const PBT_TIMEOUT = 30_000;

describe("Property 8: Tab 切换与 URL 查询参数同步 round-trip", () => {
  for (const pageConfig of PAGE_CONFIGS) {
    const { name, validTabs, defaultTab, Component, basePath, tabLabels } = pageConfig;

    describe(`${name} 页面`, () => {
      // 生成器：从有效 tab 值中随机选取
      const tabArb = fc.constantFrom(...validTabs);

      it("设置 ?tab=X 后，激活的 Tab 应为 X", () => {
        fc.assert(
          fc.property(tabArb, (tab) => {
            cleanup();
            render(
              <MemoryRouter initialEntries={[`${basePath}?tab=${tab}`]}>
                <Component />
              </MemoryRouter>,
            );

            // Ant Design Tabs 的激活 tab 有 .ant-tabs-tab-active 类
            const activeTab = document.querySelector(".ant-tabs-tab-active");
            expect(activeTab).not.toBeNull();
            expect(activeTab!.textContent).toContain(tabLabels[tab]);

            cleanup();
          }),
          { numRuns: PBT_NUM_RUNS },
        );
      }, PBT_TIMEOUT);

      it("点击 Tab Y 后，URL 查询参数应更新为 ?tab=Y", () => {
        fc.assert(
          fc.property(tabArb, tabArb, (initialTab, targetTab) => {
            cleanup();
            let currentSearch = "";

            render(
              <MemoryRouter initialEntries={[`${basePath}?tab=${initialTab}`]}>
                <Component />
                <LocationSpy onLocation={(s) => { currentSearch = s; }} />
              </MemoryRouter>,
            );

            // 找到目标 Tab 并点击
            const tabElements = document.querySelectorAll(".ant-tabs-tab");
            let targetTabEl: Element | null = null;
            for (const el of tabElements) {
              if (el.textContent?.includes(tabLabels[targetTab])) {
                targetTabEl = el;
                break;
              }
            }
            expect(targetTabEl).not.toBeNull();
            fireEvent.click(targetTabEl!);

            // 验证 URL 参数已更新
            const params = new URLSearchParams(currentSearch);
            expect(params.get("tab")).toBe(targetTab);

            cleanup();
          }),
          { numRuns: PBT_NUM_RUNS },
        );
      }, PBT_TIMEOUT);

      it("无效或缺失的 tab 参数应回退到默认 Tab", () => {
        // 无 tab 参数
        render(
          <MemoryRouter initialEntries={[basePath]}>
            <Component />
          </MemoryRouter>,
        );
        const activeTab1 = document.querySelector(".ant-tabs-tab-active");
        expect(activeTab1).not.toBeNull();
        expect(activeTab1!.textContent).toContain(tabLabels[defaultTab]);
        cleanup();

        // 无效 tab 参数
        render(
          <MemoryRouter initialEntries={[`${basePath}?tab=invalid`]}>
            <Component />
          </MemoryRouter>,
        );
        const activeTab2 = document.querySelector(".ant-tabs-tab-active");
        expect(activeTab2).not.toBeNull();
        expect(activeTab2!.textContent).toContain(tabLabels[defaultTab]);
        cleanup();
      });
    });
  }
});
