// useExportChildGrades Hook 单测
// 依据：02-architecture-design.md §4.2 GraphQL 接入
// 覆盖：成功提交 / mutation 错误返回 / loading 状态 / 携带 subject 变量

import {
  describe,
  it,
  expect,
  beforeAll,
  afterAll,
  afterEach,
} from "vitest";
import { renderHook, act, cleanup } from "@testing-library/react";
import {
  Provider as UrqlProvider,
  Client,
  cacheExchange,
  fetchExchange,
} from "urql";
import { graphql, HttpResponse } from "msw";
import type { ReactNode } from "react";
import { server } from "@/test/mocks/server";
import { useExportChildGrades } from "./useExportChildGrades";

function createTestClient(): Client {
  return new Client({
    url: "/api/v1/parent/v1/graphql",
    exchanges: [cacheExchange, fetchExchange],
    fetchOptions: { headers: { "X-Requested-With": "XMLHttpRequest" } },
  });
}

function renderUseExportChildGrades() {
  const client = createTestClient();
  const wrapper = ({ children }: { children: ReactNode }) => (
    <UrqlProvider value={client}>{children}</UrqlProvider>
  );
  return renderHook(() => useExportChildGrades(), { wrapper });
}

beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
afterEach(() => {
  cleanup();
  server.resetHandlers();
});
afterAll(() => server.close());

describe("useExportChildGrades", () => {
  it("初始状态 loading 为 false 且 error 为 undefined", () => {
    const { result } = renderUseExportChildGrades();
    expect(result.current.loading).toBe(false);
    expect(result.current.error).toBeUndefined();
  });

  it("成功提交返回 success=true 和下载链接", async () => {
    const { result } = renderUseExportChildGrades();

    let exportResult:
      | { success: boolean; data?: { downloadUrl: string; expiresAt: string } }
      | undefined;
    await act(async () => {
      exportResult = await result.current.exportGrades({
        childId: "student-001",
      });
    });

    expect(exportResult?.success).toBe(true);
    expect(exportResult?.data?.downloadUrl).toContain("student-001");
    expect(exportResult?.data?.expiresAt).toBeDefined();
    expect(result.current.loading).toBe(false);
    expect(result.current.error).toBeUndefined();
  });

  it("提交后 loading 最终回到 false", async () => {
    const { result } = renderUseExportChildGrades();

    let resolved = false;
    await act(async () => {
      const r = await result.current.exportGrades({ childId: "student-001" });
      resolved = r.success;
    });

    expect(resolved).toBe(true);
    expect(result.current.loading).toBe(false);
  });

  it("mutation 返回错误时返回 success=false 并设置 error", async () => {
    server.resetHandlers(
      graphql.mutation("ExportChildGrades", () =>
        HttpResponse.json(
          { errors: [{ message: "导出失败：权限不足" }] },
          { status: 200 },
        ),
      ),
    );

    const { result } = renderUseExportChildGrades();

    let exportResult:
      | { success: boolean; error?: { message: string } }
      | undefined;
    await act(async () => {
      exportResult = await result.current.exportGrades({
        childId: "student-001",
      });
    });

    expect(exportResult?.success).toBe(false);
    expect(exportResult?.error).toBeDefined();
    expect(result.current.error?.message).toContain("权限不足");
    expect(result.current.loading).toBe(false);
  });

  it("未传 subject 时变量 subject 为 null", async () => {
    let capturedVars: unknown = null;
    server.resetHandlers(
      graphql.mutation("ExportChildGrades", ({ variables }) => {
        capturedVars = variables;
        return HttpResponse.json({
          data: {
            exportChildGrades: {
              downloadUrl: "https://example.com/exports/grades.xlsx",
              expiresAt: "2026-07-13T23:59:59Z",
            },
          },
        });
      }),
    );

    const { result } = renderUseExportChildGrades();
    await act(async () => {
      await result.current.exportGrades({ childId: "student-001" });
    });

    expect(capturedVars).toEqual({
      childId: "student-001",
      subject: null,
    });
  });

  it("传入 subject 时变量携带 subject", async () => {
    let capturedVars: unknown = null;
    server.resetHandlers(
      graphql.mutation("ExportChildGrades", ({ variables }) => {
        capturedVars = variables;
        return HttpResponse.json({
          data: {
            exportChildGrades: {
              downloadUrl: "https://example.com/exports/grades-math.xlsx",
              expiresAt: "2026-07-13T23:59:59Z",
            },
          },
        });
      }),
    );

    const { result } = renderUseExportChildGrades();
    await act(async () => {
      await result.current.exportGrades({
        childId: "student-001",
        subject: "数学",
      });
    });

    expect(capturedVars).toEqual({
      childId: "student-001",
      subject: "数学",
    });
  });
});
