import "dotenv/config";
import { describe, it, expect, vi } from "vitest";
import JSZip from "jszip";

import type { Block, ProjectConfig } from "@/features/editor/state/editorStore";

const BASE_URL = "http://localhost";

// 정적 Export + main.js + /api/forms/submit 를 묶어서 검증하는 통합 테스트.
// - /api/export 로 ZIP 을 생성해서 index.html / main.js 를 추출한다.
// - jsdom DOM 에 index.html 을 주입하고, main.js 스크립트를 실제로 실행한다.
// - form.pb-form-controller 에서 submit 이벤트를 발생시키면
//   main.js 가 submit 을 가로채고 /api/forms/submit 로 fetch 를 호출해야 한다.

describe("정적 Export 폼 컨트롤러 통합", () => {
  it("Export된 index.html + main.js 에서 submit 시 /api/forms/submit 로 fetch 를 호출해야 한다", async () => {
    const blocks: Block[] = [
      {
        id: "form_1",
        type: "form",
        props: {
          kind: "contact",
          submitTarget: "internal",
          fieldIds: ["input_name"],
          submitButtonId: null,
          formWidthMode: "full",
        },
      } as any,
      {
        id: "input_name",
        type: "formInput",
        props: {
          label: "이름",
          formFieldName: "name",
          required: true,
        },
      } as any,
    ];

    const projectConfig: ProjectConfig = {
      title: "폼 통합 테스트",
      slug: "form-integration-test",
      canvasPreset: "full",
    };

    const payload = { blocks, projectConfig };

    const { POST: handleExport } = await import("@/app/api/export/route");

    const res = await handleExport(
      new Request(`${BASE_URL}/api/export`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload),
      }),
    );

    expect(res.status).toBe(200);

    const arrayBuffer = await res.arrayBuffer();
    const zip = await JSZip.loadAsync(arrayBuffer);

    const indexEntry = zip.file("index.html");
    const jsEntry = zip.file("main.js");

    expect(indexEntry).toBeTruthy();
    expect(jsEntry).toBeTruthy();

    const html = await indexEntry!.async("string");
    const mainJs = await jsEntry!.async("string");

    // jsdom DOM 구성: export 된 HTML 을 그대로 주입한다.
    document.documentElement.innerHTML = html;

    const form = document.querySelector("form.pb-form-controller") as HTMLFormElement | null;
    expect(form).not.toBeNull();

    // name 필드에 값 채우기 (FormData 에 실제 값이 들어가도록)
    const nameInput = document.querySelector('input[name="name"]') as HTMLInputElement | null;
    if (nameInput) {
      nameInput.value = "Alice";
    }

    // fetch 를 목킹하여 main.js 의 submit 가로채기 동작을 검증한다.
    const fetchMock = vi.fn(async () =>
      new Response(JSON.stringify({ ok: true, message: "ok" }), {
        status: 200,
        headers: { "Content-Type": "application/json" },
      }),
    );
    (globalThis as any).fetch = fetchMock;

    // main.js 실행 (IIFE 코드이므로 평가만 하면 즉시 pbInitFormControllers 가 동작한다.)
    // eslint-disable-next-line no-new-func
    new Function(mainJs)();

    // submit 이벤트 발생: main.js 가 이를 가로채고 fetch 를 호출해야 한다.
    const submitEvent = new Event("submit", { bubbles: true, cancelable: true });
    form!.dispatchEvent(submitEvent);

    expect(fetchMock).toHaveBeenCalledTimes(1);
    const [url, options] = fetchMock.mock.calls[0] as [any, RequestInit];

    expect(url).toBe("/api/forms/submit");
    expect(options.method).toBe("POST");
    expect(options.body).toBeInstanceOf(FormData);
  });
});
