import { describe, it, expect, afterEach, vi } from "vitest";
import { render, screen, cleanup, waitFor } from "@testing-library/react";

import AllProjectSubmissionsPage from "@/app/projects/submissions/page";

// /projects/submissions 페이지 유닛 테스트
// - /api/projects/submissions 응답을 테이블로 렌더링하는지
// - 401/404/기타 에러에 대해 올바른 메시지를 표시하는지
// - 상단에 "프로젝트 목록" 링크가 있고 클릭 시 /projects 로 이동하는지

export const pushMock = vi.fn();

vi.mock("next/navigation", () => {
  return {
    __esModule: true,
    useRouter: () => ({ push: pushMock }),
  };
});

afterEach(() => {
  cleanup();
  vi.unstubAllGlobals();
  vi.clearAllMocks();
});

describe("AllProjectSubmissionsPage - 전체 폼 제출 내역", () => {
  it("/api/projects/submissions 응답을 프로젝트/필드 정보가 포함된 테이블로 렌더링해야 한다", async () => {
    const submissions = [
      {
        id: "1",
        createdAt: "2025-01-01T12:00:00.000Z",
        projectSlug: "proj-1",
        projectTitle: "프로젝트 1",
        payload: {
          name: "홍길동",
          email: "user@example.com",
          phone: "010-1234-5678",
          birthdate: "1990-01-01",
          message: "안녕하세요",
        },
      },
      {
        id: "2",
        createdAt: "2025-01-02T08:30:00.000Z",
        projectSlug: "proj-2",
        projectTitle: "프로젝트 2",
        payload: {
          name: "김철수",
          email: "another@example.com",
          phone: "010-0000-0000",
          birthdate: "1995-05-05",
          message: "두 번째 문의입니다.",
        },
      },
    ];

    const fetchMock = vi.fn().mockResolvedValue(
      new Response(JSON.stringify(submissions), {
        status: 200,
        headers: { "Content-Type": "application/json" },
      }),
    );

    vi.stubGlobal("fetch", fetchMock as any);

    render(<AllProjectSubmissionsPage />);

    await waitFor(() => {
      expect(fetchMock).toHaveBeenCalledTimes(1);
    });

    const [url, options] = fetchMock.mock.calls[0] as any;
    expect(url).toBe("/api/projects/submissions");
    expect(options).toBeUndefined();

    expect(await screen.findByText("전체 폼 제출 내역")).toBeTruthy();

    expect(screen.getByText("프로젝트 1")).toBeTruthy();
    expect(screen.getByText("proj-1")).toBeTruthy();
    expect(screen.getByText("홍길동")).toBeTruthy();
    expect(screen.getByText("user@example.com")).toBeTruthy();
    expect(screen.getByText("010-1234-5678")).toBeTruthy();
    expect(screen.getByText("1990-01-01")).toBeTruthy();
    expect(screen.getByText("message: 안녕하세요")).toBeTruthy();

    expect(screen.getByText("프로젝트 2")).toBeTruthy();
    expect(screen.getByText("proj-2")).toBeTruthy();
    expect(screen.getByText("김철수")).toBeTruthy();
    expect(screen.getByText("another@example.com")).toBeTruthy();
    expect(screen.getByText("010-0000-0000")).toBeTruthy();
    expect(screen.getByText("1995-05-05")).toBeTruthy();
    expect(screen.getByText("message: 두 번째 문의입니다.")).toBeTruthy();
  });

  it("API 가 401 을 반환하면 로그인 페이지로 리다이렉트해야 한다", async () => {
    const fetchMock = vi.fn().mockResolvedValue(
      new Response(
        JSON.stringify({ message: "폼 제출 내역을 조회하려면 로그인이 필요합니다." }),
        {
          status: 401,
          headers: { "Content-Type": "application/json" },
        },
      ),
    );

    vi.stubGlobal("fetch", fetchMock as any);

    render(<AllProjectSubmissionsPage />);

    await waitFor(() => {
      expect(fetchMock).toHaveBeenCalledTimes(1);
      expect(pushMock).toHaveBeenCalledWith("/login");
    });
  });

  it("API 가 500 등을 반환하면 에러 메시지를 화면에 표시해야 한다", async () => {
    const fetchMock = vi.fn().mockResolvedValue(
      new Response(JSON.stringify({ message: "서버 에러" }), {
        status: 500,
        headers: { "Content-Type": "application/json" },
      }),
    );

    vi.stubGlobal("fetch", fetchMock as any);

    render(<AllProjectSubmissionsPage />);

    const errorText = await screen.findByText(
      "폼 제출 내역을 불러오는 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.",
    );

    expect(errorText).toBeTruthy();
  });

  it("상단에 '프로젝트 목록' 링크가 있고 클릭 시 /projects 로 이동해야 한다", async () => {
    const fetchMock = vi.fn().mockResolvedValue(
      new Response(JSON.stringify([]), {
        status: 200,
        headers: { "Content-Type": "application/json" },
      }),
    );

    vi.stubGlobal("fetch", fetchMock as any);

    render(<AllProjectSubmissionsPage />);

    const backLink = await screen.findByRole("link", { name: "프로젝트 목록" });
    expect(backLink).toBeTruthy();

    backLink.click();

    await waitFor(() => {
      expect(pushMock).toHaveBeenCalledWith("/projects");
    });
  });
});
