import { describe, it, expect, afterEach, vi } from "vitest";
import { render, screen, fireEvent, cleanup, waitFor } from "@testing-library/react";
import { PublicPageRenderer } from "@/features/editor/components/PublicPageRenderer";
import type { Block } from "@/features/editor/state/editorStore";

// PublicPageRenderer 폼 제출 UX TDD
// - 성공 응답 시 FormBlockProps 의 successMessage 를 success 스타일로 표시해야 한다.
// - 실패 응답 시 FormBlockProps 의 errorMessage 를 error 스타일로 표시해야 한다.

describe("PublicPageRenderer - 폼 제출 메시지", () => {
  afterEach(() => {
    cleanup();
    // fetch 목 초기화
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    (globalThis as any).fetch = undefined;
  });

  it("성공 응답 시 FormBlock 의 successMessage 를 성공 메시지로 렌더해야 한다", async () => {
    const blocks: Block[] = [
      {
        id: "form_success",
        type: "form",
        props: {
          kind: "contact",
          submitTarget: "internal",
          successMessage: "폼 성공 메시지 (config)",
          errorMessage: "폼 에러 메시지 (config)",
          fieldIds: ["field_name"],
          requiredFieldIds: ["field_name"],
          submitButtonId: "submit_btn",
        } as any,
      },
      {
        id: "field_name",
        type: "formInput",
        props: {
          label: "이름",
          formFieldName: "name",
          required: true,
        } as any,
      },
      {
        id: "submit_btn",
        type: "button",
        props: {
          label: "제출하기",
          href: "#",
        } as any,
      },
    ];

    const fetchMock = vi.fn(async () =>
      new Response("ok", {
        status: 200,
        headers: { "Content-Type": "text/plain" },
      }),
    );
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    (globalThis as any).fetch = fetchMock;

    render(<PublicPageRenderer blocks={blocks} />);

    const nameInput = screen.getByLabelText("이름") as HTMLInputElement;
    fireEvent.change(nameInput, { target: { value: "홍길동" } });

    const submitButton = screen.getByRole("link", { name: "제출하기" });
    expect(submitButton).toBeTruthy();

    fireEvent.click(submitButton);

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

    await waitFor(() => {
      const msg = screen.getByText("폼 성공 메시지 (config)");
      expect(msg).toBeTruthy();
    });
  });

  it("실패 응답 시 FormBlock 의 errorMessage 를 에러 메시지로 렌더해야 한다", async () => {
    const blocks: Block[] = [
      {
        id: "form_error",
        type: "form",
        props: {
          kind: "contact",
          submitTarget: "internal",
          successMessage: "폼 성공 메시지 (config)",
          errorMessage: "폼 에러 메시지 (config)",
          fieldIds: ["field_name"],
          requiredFieldIds: ["field_name"],
          submitButtonId: "submit_btn",
        } as any,
      },
      {
        id: "field_name",
        type: "formInput",
        props: {
          label: "이름",
          formFieldName: "name",
          required: true,
        } as any,
      },
      {
        id: "submit_btn",
        type: "button",
        props: {
          label: "제출하기",
          href: "#",
        } as any,
      },
    ];

    const fetchMock = vi.fn(async () =>
      new Response("error", {
        status: 500,
        headers: { "Content-Type": "text/plain" },
      }),
    );
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    (globalThis as any).fetch = fetchMock;

    render(<PublicPageRenderer blocks={blocks} />);

    const nameInput = screen.getByLabelText("이름") as HTMLInputElement;
    fireEvent.change(nameInput, { target: { value: "홍길동" } });

    const submitButton = screen.getByRole("link", { name: "제출하기" });
    expect(submitButton).toBeTruthy();

    fireEvent.click(submitButton);

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

    await waitFor(() => {
      const errorMsg = screen.getByText("폼 에러 메시지 (config)");
      expect(errorMsg).toBeTruthy();
    });
  });

  it("필수 필드가 비어 있고 errorMessage 가 없으면 기본 문구에 필수 항목 라벨을 포함해야 한다", async () => {
    const blocks: Block[] = [
      {
        id: "form_required_default_msg",
        type: "form",
        props: {
          kind: "contact",
          submitTarget: "internal",
          successMessage: "폼 성공 메시지 (config)",
          fieldIds: ["field_email"],
          requiredFieldIds: ["field_email"],
          submitButtonId: "submit_btn",
        } as any,
      },
      {
        id: "field_email",
        type: "formInput",
        props: {
          label: "이메일",
          formFieldName: "email",
          required: true,
        } as any,
      },
      {
        id: "submit_btn",
        type: "button",
        props: {
          label: "제출하기",
          href: "#",
        } as any,
      },
    ];

    const fetchMock = vi.fn(async () =>
      new Response("ok", {
        status: 200,
        headers: { "Content-Type": "text/plain" },
      }),
    );
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    (globalThis as any).fetch = fetchMock;

    render(<PublicPageRenderer blocks={blocks} />);

    const submitButton = screen.getByRole("link", { name: "제출하기" });
    expect(submitButton).toBeTruthy();

    fireEvent.click(submitButton);

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

    await waitFor(() => {
      const errorMsg = screen.getByText(/다음 필수 항목을 입력해 주세요:\s*-\s*이메일/);
      expect(errorMsg).toBeTruthy();
    });
  });

  it("필수 필드가 비어 있으면 요청을 보내지 않고 필수 항목 안내 메시지를 표시해야 한다 (errorMessage 설정 시)", async () => {
    const blocks: Block[] = [
      {
        id: "form_required",
        type: "form",
        props: {
          kind: "contact",
          submitTarget: "internal",
          successMessage: "폼 성공 메시지 (config)",
          errorMessage: "폼 에러 메시지 (config)",
          fieldIds: ["field_name"],
          requiredFieldIds: ["field_name"],
          submitButtonId: "submit_btn",
        } as any,
      },
      {
        id: "field_name",
        type: "formInput",
        props: {
          label: "이름",
          formFieldName: "name",
          required: true,
        } as any,
      },
      {
        id: "submit_btn",
        type: "button",
        props: {
          label: "제출하기",
          href: "#",
        } as any,
      },
    ];

    const fetchMock = vi.fn(async () =>
      new Response("ok", {
        status: 200,
        headers: { "Content-Type": "text/plain" },
      }),
    );
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    (globalThis as any).fetch = fetchMock;

    render(<PublicPageRenderer blocks={blocks} />);

    const submitButton = screen.getByRole("link", { name: "제출하기" });
    expect(submitButton).toBeTruthy();

    // 이름 필드를 비운 채로 제출한다.
    fireEvent.click(submitButton);

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

    await waitFor(() => {
      const errorMsg = screen.getByText(/다음 필수 항목을 입력해 주세요:\s*-\s*이름/);
      expect(errorMsg).toBeTruthy();
    });
  });
});
