/**
 * useCompareData Hook 单元测试
 */

import { describe, it, expect, vi, beforeEach } from "vitest";
import { renderHook, waitFor, act } from "@testing-library/react";
import { SWRConfig } from "swr";
import type { ReactNode } from "react";

vi.mock("@/lib/api/client", () => ({
  fetchWithAuth: vi.fn(),
}));

import { fetchWithAuth } from "@/lib/api/client";
const mockFetchWithAuth = vi.mocked(fetchWithAuth);

vi.mock("next-auth/react", () => ({
  useSession: vi.fn(() => ({
    data: { accessToken: "test-token" },
    status: "authenticated",
  })),
}));

import { useCompareData } from "@/lib/hooks/use-compare-data";
import type { BrandListResponse, CompareResponse } from "@/types/brand";

const noRetryOptions = { shouldRetryOnError: false };

/** 使用独立 SWR 缓存的 wrapper，避免测试间缓存冲突 */
function createWrapper() {
  return ({ children }: { children: ReactNode }) =>
    SWRConfig({
      value: { provider: () => new Map() },
      children,
    });
}

describe("useCompareData", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  const mockBrandsResponse: BrandListResponse = {
    items: [
      {
        id: "brand-1",
        name: "测试品牌",
        aliases: [],
        platforms: ["wenxin"],
        frequency: "weekly",
        status: "active",
        score: 80,
        last_queried_at: null,
        next_query_at: null,
        created_at: "2024-01-01",
      },
    ],
    total: 1,
  };

  const mockCompareResponse: CompareResponse = {
    brand_id: "brand-1",
    brand_name: "测试品牌",
    items: [
      {
        entity_id: "brand-1",
        entity_name: "测试品牌",
        entity_type: "brand",
        mention_rate_score: 70,
        sov_score: 65,
        quality_score: 80,
        overall_score: 75,
        citation_count: 100,
        dimensions: [],
        overall_trend: "up",
        overall_trend_value: 5,
      },
    ],
    radar_data: [],
  };

  it("应返回品牌列表数据", async () => {
    mockFetchWithAuth.mockImplementation((url: string) => {
      if (url.includes("/api/v1/brands")) return Promise.resolve(mockBrandsResponse);
      return Promise.resolve({});
    });

    const { result } = renderHook(
      () => useCompareData({ swrOptions: noRetryOptions }),
      { wrapper: createWrapper() }
    );

    await waitFor(() => {
      expect(result.current.brands).toEqual(mockBrandsResponse.items);
    });
  });

  it("selectedBrandId 为空时应暂停对比数据请求", () => {
    mockFetchWithAuth.mockResolvedValue(mockBrandsResponse);

    const { result } = renderHook(
      () => useCompareData({ swrOptions: noRetryOptions }),
      { wrapper: createWrapper() }
    );

    expect(result.current.compareData).toBeUndefined();
  });

  it("selectedBrandId 存在时应获取对比数据", async () => {
    mockFetchWithAuth.mockImplementation((url: string) => {
      if (url.includes("/compare")) return Promise.resolve(mockCompareResponse);
      return Promise.resolve(mockBrandsResponse);
    });

    const { result } = renderHook(
      () => useCompareData({ initialBrandId: "brand-1", swrOptions: noRetryOptions }),
      { wrapper: createWrapper() }
    );

    await waitFor(() => {
      expect(result.current.compareData).toEqual(mockCompareResponse);
    });
  });

  it("应正确暴露 loading 状态", async () => {
    mockFetchWithAuth.mockImplementation((url: string) => {
      if (url.includes("/compare")) return Promise.resolve(mockCompareResponse);
      return Promise.resolve(mockBrandsResponse);
    });

    const { result } = renderHook(
      () => useCompareData({ initialBrandId: "brand-1", swrOptions: noRetryOptions }),
      { wrapper: createWrapper() }
    );

    await waitFor(() => {
      expect(result.current.isLoading).toBe(false);
    });
  });

  it("应正确暴露 error 状态", async () => {
    mockFetchWithAuth.mockRejectedValue(new Error("网络错误"));

    const { result } = renderHook(
      () => useCompareData({ swrOptions: noRetryOptions }),
      { wrapper: createWrapper() }
    );

    await waitFor(() => {
      expect(result.current.error).toBeDefined();
      expect(result.current.error?.message).toBe("网络错误");
    });
  });

  it("setSelectedBrandId 应更新选中品牌", async () => {
    mockFetchWithAuth.mockImplementation((url: string) => {
      if (url.includes("/compare")) return Promise.resolve(mockCompareResponse);
      return Promise.resolve(mockBrandsResponse);
    });

    const { result } = renderHook(
      () => useCompareData({ swrOptions: noRetryOptions }),
      { wrapper: createWrapper() }
    );

    await waitFor(() => {
      expect(result.current.brands.length).toBeGreaterThan(0);
    });

    act(() => {
      result.current.setSelectedBrandId("brand-1");
    });

    expect(result.current.selectedBrandId).toBe("brand-1");
  });

  it("应提供 refresh 方法刷新数据", async () => {
    mockFetchWithAuth.mockResolvedValue(mockBrandsResponse);

    const { result } = renderHook(
      () => useCompareData({ swrOptions: noRetryOptions }),
      { wrapper: createWrapper() }
    );

    await waitFor(() => {
      expect(result.current.isLoading).toBe(false);
    });

    expect(typeof result.current.refreshBrands).toBe("function");
    expect(typeof result.current.refreshCompare).toBe("function");
  });
});
