import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import { render, screen, fireEvent, cleanup, waitFor } from "@testing-library/react";
import type { Block, ProjectConfig } from "@/features/editor/state/editorStore";
import PreviewPage from "@/app/preview/page";

// PreviewPage Export ZIP TDD
// - 프리뷰 헤더에 "페이지 파일로 내보내기 (ZIP)" 버튼이 노출되어야 한다.
// - 버튼 클릭 시 /api/export 로 blocks + projectConfig 를 payload 로 POST 요청을 보내야 한다.

let mockState: any;

beforeEach(() => {
  const baseProjectConfig: ProjectConfig = {
    title: "프리뷰 Export 테스트",
    slug: "preview-export-test",
    canvasPreset: "full",
  } as ProjectConfig;

  mockState = {
    blocks: [
      {
        id: "blk_text_1",
        type: "text",
        props: {
          text: "프리뷰 Export 본문",
          align: "left",
          size: "base",
        },
      },
    ] as Block[],
    projectConfig: baseProjectConfig,
  };
});

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

vi.mock("@/features/editor/state/editorStore", () => {
  const useEditorStore = (selector: (state: any) => any) => selector(mockState);
  return {
    __esModule: true,
    useEditorStore,
  };
});

vi.mock("next/link", () => {
  return {
    __esModule: true,
    default: ({ href, children }: any) => <a href={href}>{children}</a>,
  };
});

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

describe("PreviewPage - ZIP Export", () => {
  it("프리뷰 헤더에 프로젝트 목록 링크가 노출되고 /projects 로 연결되어야 한다", () => {
    render(<PreviewPage />);

    const link = screen.getByText("프로젝트 목록");
    expect(link).toBeTruthy();
    expect(link.closest("a")?.getAttribute("href")).toBe("/projects");
  });

  it("프리뷰 헤더에 ZIP Export 버튼이 노출되어야 한다", () => {
    render(<PreviewPage />);

    const exportButton = screen.getByText("페이지 파일로 내보내기 (ZIP)");
    expect(exportButton).toBeTruthy();
  });

  it("ZIP Export 버튼 클릭 시 /api/export 로 blocks + projectConfig 를 payload 로 POST 해야 한다", async () => {
    const fetchMock = vi.fn().mockResolvedValue({
      ok: true,
      // JSDOM 환경에서 blob() 호출을 안전하게 처리하기 위한 최소 mock
      blob: vi.fn().mockResolvedValue(new Blob(["dummy-zip"])),
    } as any);

    vi.stubGlobal("fetch", fetchMock);

    render(<PreviewPage />);

    const exportButton = screen.getByText("페이지 파일로 내보내기 (ZIP)");
    fireEvent.click(exportButton);

    await waitFor(() => {
      expect(
        fetchMock.mock.calls.some(
          ([url, options]: any[]) => url === "/api/export" && options?.method === "POST",
        ),
      ).toBe(true);
    });

    const exportCall = fetchMock.mock.calls.find(
      ([url, options]: any[]) => url === "/api/export" && options?.method === "POST",
    ) as any;

    const [url, options] = exportCall;
    expect(url).toBe("/api/export");
    expect(options.method).toBe("POST");
    expect(options.headers["Content-Type"]).toBe("application/json");

    const parsed = JSON.parse(options.body);
    expect(Array.isArray(parsed.blocks)).toBe(true);
    expect(parsed.blocks[0].id).toBe("blk_text_1");
    expect(parsed.projectConfig.slug).toBe("preview-export-test");
  });
});
