/**
 * 单元测试：Dashboard 页面 + DbHealthCard 组件
 *
 * _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5_
 *
 * - 测试 4 个区块正确渲染
 * - 测试跳转链接指向正确路由
 * - 测试 DbHealthCard connected/disconnected/timeout 状态渲染
 */

import { describe, it, expect, vi, beforeAll, beforeEach } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import "@testing-library/jest-dom/vitest";
import { MemoryRouter } from "react-router-dom";
import React from "react";
import DbHealthCard from "../components/DbHealthCard";
import type { DbHealthItem } from "../api/dbHealth";

/* ------------------------------------------------------------------ */
/*  Ant Design jsdom 兼容：polyfill window.matchMedia                   */
/* ------------------------------------------------------------------ */

beforeAll(() => {
  Object.defineProperty(window, "matchMedia", {
    writable: true,
    value: vi.fn().mockImplementation((query: string) => ({
      matches: false,
      media: query,
      onchange: null,
      addListener: vi.fn(),
      removeListener: vi.fn(),
      addEventListener: vi.fn(),
      removeEventListener: vi.fn(),
      dispatchEvent: vi.fn(),
    })),
  });
});

/* ------------------------------------------------------------------ */
/*  Mock 所有 Dashboard 依赖的 API 模块                                  */
/* ------------------------------------------------------------------ */

vi.mock("../api/opsPanel", () => ({
  fetchSystemInfo: vi.fn().mockResolvedValue({
    cpu_percent: 25,
    memory_total_gb: 16,
    memory_used_gb: 8,
    memory_percent: 50,
    disk_total_gb: 500,
    disk_used_gb: 250,
    disk_percent: 50,
    boot_time: "2026-01-01T00:00:00",
  }),
  fetchServicesStatus: vi.fn().mockResolvedValue([
    {
      env: "prod",
      label: "生产环境",
      running: true,
      pid: 1234,
      port: 8000,
      uptime_seconds: 3600,
      memory_mb: 256,
      cpu_percent: 10,
    },
  ]),
  fetchGitInfo: vi.fn().mockResolvedValue([
    {
      env: "prod",
      branch: "main",
      last_commit_hash: "abc1234",
      last_commit_message: "test commit",
      last_commit_time: "2026-01-01T00:00:00",
      has_local_changes: false,
    },
  ]),
  startService: vi.fn(),
  stopService: vi.fn(),
  restartService: vi.fn(),
  gitPull: vi.fn(),
  syncDeps: vi.fn(),
}));

vi.mock("../api/dbHealth", () => ({
  fetchDbHealth: vi.fn().mockResolvedValue([
    {
      db_name: "etl_feiqiu",
      status: "connected",
      active_connections: 5,
      idle_connections: 10,
      db_size_mb: 128.5,
      slow_query_count: 2,
    },
    {
      db_name: "test_etl_feiqiu",
      status: "disconnected",
      active_connections: null,
      idle_connections: null,
      db_size_mb: null,
      slow_query_count: null,
    },
  ]),
}));

vi.mock("../api/adminAI", () => ({
  getTriggerJobs: vi.fn().mockResolvedValue({
    items: [],
    total: 0,
    page: 1,
    page_size: 50,
    today_skipped_duplicates: 0,
  }),
}));

// Mock AIDashboard 为简单占位，避免其内部 API 调用
vi.mock("../pages/AIDashboard", () => ({
  default: () => <div data-testid="ai-dashboard-mock">AIDashboard</div>,
}));

/* ------------------------------------------------------------------ */
/*  Dashboard 页面测试                                                  */
/* ------------------------------------------------------------------ */

describe("Dashboard 页面 (Requirements 2.1, 2.2)", () => {
  let Dashboard: React.FC;

  beforeEach(async () => {
    vi.clearAllMocks();
    const mod = await import("../pages/Dashboard");
    Dashboard = mod.default;
  });

  it("渲染 4 个区块：OpsPanel 子组件、DbHealthCard、AI 运行总览、AI 调度摘要", async () => {
    render(
      <MemoryRouter initialEntries={["/dashboard"]}>
        <Dashboard />
      </MemoryRouter>,
    );

    // 区块 1：OpsPanel 子组件 — 页面标题"运行状态"
    expect(await screen.findByText("运行状态")).toBeInTheDocument();

    // 区块 2：数据库健康监控
    expect(screen.getByText("数据库健康监控")).toBeInTheDocument();

    // 区块 3：AI 运行总览（mocked AIDashboard）
    expect(screen.getByText("AI 运行总览")).toBeInTheDocument();
    expect(screen.getByTestId("ai-dashboard-mock")).toBeInTheDocument();

    // 区块 4：AI 调度摘要（Divider + Card title 各出现一次）
    const summaryElements = screen.getAllByText("AI 调度摘要");
    expect(summaryElements.length).toBeGreaterThanOrEqual(1);
    expect(screen.getByText("今日触发数")).toBeInTheDocument();
    expect(screen.getByText("今日成功率")).toBeInTheDocument();
  });

  it("跳转链接：ETL 状态详情、触发器详情、AI 调度详情", async () => {
    render(
      <MemoryRouter initialEntries={["/dashboard"]}>
        <Dashboard />
      </MemoryRouter>,
    );

    await screen.findByText("运行状态");

    expect(screen.getByText(/ETL 状态详情/)).toBeInTheDocument();
    expect(screen.getByText(/触发器详情/)).toBeInTheDocument();

    // AI 调度详情出现两次（顶部按钮 + 底部链接），取第一个
    const aiButtons = screen.getAllByText(/AI 调度详情/);
    expect(aiButtons.length).toBeGreaterThanOrEqual(1);
  });
});

/* ------------------------------------------------------------------ */
/*  DbHealthCard 组件测试（纯展示组件，不需要 mock API）                   */
/* ------------------------------------------------------------------ */

describe("DbHealthCard — connected 状态 (Requirements 2.3, 2.4)", () => {
  const connectedItems: DbHealthItem[] = [
    {
      db_name: "etl_feiqiu",
      status: "connected",
      active_connections: 5,
      idle_connections: 10,
      db_size_mb: 128.5,
      slow_query_count: 2,
    },
    {
      db_name: "zqyy_app",
      status: "connected",
      active_connections: 3,
      idle_connections: 7,
      db_size_mb: 256.0,
      slow_query_count: 0,
    },
  ];

  it("为每个 connected 数据库渲染卡片，显示「已连接」标签", () => {
    render(<DbHealthCard items={connectedItems} />);

    expect(screen.getByText("etl_feiqiu")).toBeInTheDocument();
    expect(screen.getByText("zqyy_app")).toBeInTheDocument();

    const connectedTags = screen.getAllByText("已连接");
    expect(connectedTags).toHaveLength(2);
  });

  it("展示连接池指标（活跃/空闲连接数）", () => {
    render(<DbHealthCard items={connectedItems} />);

    expect(screen.getByText(/活跃 5/)).toBeInTheDocument();
    expect(screen.getByText(/空闲 10/)).toBeInTheDocument();
  });

  it("展示数据库大小和慢查询数量", () => {
    render(<DbHealthCard items={connectedItems} />);

    const sizeLabels = screen.getAllByText("数据库大小");
    expect(sizeLabels.length).toBeGreaterThanOrEqual(1);

    const slowLabels = screen.getAllByText(/慢查询/);
    expect(slowLabels.length).toBeGreaterThanOrEqual(1);
  });
});

describe("DbHealthCard — disconnected 状态 (Requirement 2.5)", () => {
  const disconnectedItems: DbHealthItem[] = [
    {
      db_name: "test_etl_feiqiu",
      status: "disconnected",
      active_connections: null,
      idle_connections: null,
      db_size_mb: null,
      slow_query_count: null,
    },
  ];

  it("disconnected 数据库显示「未连接」标签", () => {
    render(<DbHealthCard items={disconnectedItems} />);

    expect(screen.getByText("test_etl_feiqiu")).toBeInTheDocument();
    expect(screen.getByText("未连接")).toBeInTheDocument();
  });

  it("disconnected 数据库显示无法获取指标提示", () => {
    render(<DbHealthCard items={disconnectedItems} />);

    expect(screen.getByText("数据库未连接，无法获取指标")).toBeInTheDocument();
  });
});

describe("DbHealthCard — timeout 状态", () => {
  it("超时时显示「加载超时」标签", () => {
    render(<DbHealthCard items={[]} timeout={true} />);

    expect(screen.getByText("加载超时")).toBeInTheDocument();
  });

  it("超时时显示重试按钮，点击触发 onRetry", () => {
    const onRetry = vi.fn();
    render(<DbHealthCard items={[]} timeout={true} onRetry={onRetry} />);

    const retryBtn = screen.getByText("重试");
    expect(retryBtn).toBeInTheDocument();

    fireEvent.click(retryBtn);
    expect(onRetry).toHaveBeenCalledOnce();
  });
});

describe("DbHealthCard — mixed 状态（connected + disconnected）", () => {
  const mixedItems: DbHealthItem[] = [
    {
      db_name: "etl_feiqiu",
      status: "connected",
      active_connections: 5,
      idle_connections: 10,
      db_size_mb: 128.5,
      slow_query_count: 2,
    },
    {
      db_name: "test_etl_feiqiu",
      status: "disconnected",
      active_connections: null,
      idle_connections: null,
      db_size_mb: null,
      slow_query_count: null,
    },
  ];

  it("同时渲染 connected 和 disconnected 卡片", () => {
    render(<DbHealthCard items={mixedItems} />);

    expect(screen.getByText("已连接")).toBeInTheDocument();
    expect(screen.getByText("未连接")).toBeInTheDocument();
    expect(screen.getByText("etl_feiqiu")).toBeInTheDocument();
    expect(screen.getByText("test_etl_feiqiu")).toBeInTheDocument();
  });
});
