import { describe, it, expect, afterEach, vi } from "vitest";
import { render, screen, fireEvent, cleanup } from "@testing-library/react";
import { BlocksSidebar } from "@/app/editor/panels/BlocksSidebar";

// BlocksSidebar 템플릿 버튼 TDD
// - 각 템플릿 추가 버튼이 대응하는 editorStore 액션(add*TemplateSection)을 호출하는지 검증한다.

const templateActions = {
  addHeroTemplateSection: vi.fn(),
  addFeaturesTemplateSection: vi.fn(),
  addCtaTemplateSection: vi.fn(),
  addFaqTemplateSection: vi.fn(),
  addPricingTemplateSection: vi.fn(),
  addTestimonialsTemplateSection: vi.fn(),
  addBlogTemplateSection: vi.fn(),
  addTeamTemplateSection: vi.fn(),
  addFooterTemplateSection: vi.fn(),
};

// BlocksSidebar 가 사용하는 나머지 액션들도 더미 함수로 채워둔다.
const otherActions = {
  addTextBlock: vi.fn(),
  addButtonBlock: vi.fn(),
  addImageBlock: vi.fn(),
  addVideoBlock: vi.fn(),
  addDividerBlock: vi.fn(),
  addListBlock: vi.fn(),
  addSectionBlock: vi.fn(),
  addFormBlock: vi.fn(),
  addFormInputBlock: vi.fn(),
  addFormSelectBlock: vi.fn(),
  addFormCheckboxBlock: vi.fn(),
  addFormRadioBlock: vi.fn(),
};

const mockState = {
  ...templateActions,
  ...otherActions,
};

vi.mock("@/features/editor/state/editorStore", () => {
  return {
    __esModule: true,
    // useEditorStore(selector) 형태로 사용되므로, selector 에 mockState 를 넘겨준다.
    useEditorStore: (selector: (state: typeof mockState) => unknown) => selector(mockState),
  };
});

describe("BlocksSidebar - 템플릿 버튼", () => {
  afterEach(() => {
    cleanup();
    Object.values(templateActions).forEach((fn) => fn.mockReset());
  });

  it("Hero 템플릿 버튼 클릭 시 addHeroTemplateSection 이 호출되어야 한다", () => {
    render(<BlocksSidebar />);
    const button = screen.getByRole("button", { name: "Hero 템플릿" });
    fireEvent.click(button);

    expect(templateActions.addHeroTemplateSection).toHaveBeenCalledTimes(1);
  });

  it("Features 템플릿 버튼 클릭 시 addFeaturesTemplateSection 이 호출되어야 한다", () => {
    render(<BlocksSidebar />);
    const button = screen.getByRole("button", { name: "기능 템플릿" });
    fireEvent.click(button);

    expect(templateActions.addFeaturesTemplateSection).toHaveBeenCalledTimes(1);
  });

  it("CTA 템플릿 버튼 클릭 시 addCtaTemplateSection 이 호출되어야 한다", () => {
    render(<BlocksSidebar />);
    const button = screen.getByRole("button", { name: "CTA 템플릿" });
    fireEvent.click(button);

    expect(templateActions.addCtaTemplateSection).toHaveBeenCalledTimes(1);
  });

  it("FAQ/Pricing/Testimonials/Blog/Team/Footer 템플릿 버튼도 각각의 액션을 호출해야 한다", () => {
    render(<BlocksSidebar />);
    fireEvent.click(screen.getByRole("button", { name: "FAQ 템플릿" }));
    fireEvent.click(screen.getByRole("button", { name: "상품 템플릿" }));
    fireEvent.click(screen.getByRole("button", { name: "후기 템플릿" }));
    fireEvent.click(screen.getByRole("button", { name: "블로그 템플릿" }));
    fireEvent.click(screen.getByRole("button", { name: "Team 템플릿" }));
    fireEvent.click(screen.getByRole("button", { name: "Footer 템플릿" }));

    expect(templateActions.addFaqTemplateSection).toHaveBeenCalledTimes(1);
    expect(templateActions.addPricingTemplateSection).toHaveBeenCalledTimes(1);
    expect(templateActions.addTestimonialsTemplateSection).toHaveBeenCalledTimes(1);
    expect(templateActions.addBlogTemplateSection).toHaveBeenCalledTimes(1);
    expect(templateActions.addTeamTemplateSection).toHaveBeenCalledTimes(1);
    expect(templateActions.addFooterTemplateSection).toHaveBeenCalledTimes(1);
  });

  it("템플릿 섹션에는 각 템플릿의 용도를 설명하는 텍스트가 함께 표시되어야 한다", () => {
    render(<BlocksSidebar />);

    expect(screen.getByText("페이지 상단 Hero 섹션 (큰 제목 + 서브텍스트 + 버튼)"));
    expect(screen.getByText("3컬럼 기능 소개 섹션"));
    expect(screen.getByText("콜투액션(CTA) 섹션"));
    expect(screen.getByText("자주 묻는 질문(FAQ) 섹션"));
    expect(screen.getByText("요금제/플랜 소개 섹션"));
    expect(screen.getByText("고객 후기(Testimonials) 섹션"));
    expect(screen.getByText("블로그 포스트 목록 섹션"));
    expect(screen.getByText("팀 소개 섹션"));
    expect(screen.getByText("페이지 푸터 섹션"));
  });

  it("비디오 버튼 클릭 시 addVideoBlock 이 호출되어야 한다", () => {
    render(<BlocksSidebar />);
    const button = screen.getByRole("button", { name: "비디오" });
    fireEvent.click(button);

    expect(otherActions.addVideoBlock).toHaveBeenCalledTimes(1);
  });

  it("템플릿들은 카테고리별로 그룹 헤더를 가져야 한다", () => {
    render(<BlocksSidebar />);

    expect(screen.getByText("히어로 · CTA")).toBeDefined();
    expect(screen.getByText("콘텐츠 섹션")).toBeDefined();
    expect(screen.getByText("신뢰/소개")).toBeDefined();
    expect(screen.getByText("푸터/기타")).toBeDefined();
  });

  it("각 템플릿 카드에는 미니 썸네일(레이아웃 힌트)가 렌더링되어야 한다", () => {
    render(<BlocksSidebar />);

    expect(screen.getByTestId("template-preview-hero")).toBeDefined();
    expect(screen.getByTestId("template-preview-features")).toBeDefined();
    expect(screen.getByTestId("template-preview-cta")).toBeDefined();
    expect(screen.getByTestId("template-preview-faq")).toBeDefined();
    expect(screen.getByTestId("template-preview-pricing")).toBeDefined();
    expect(screen.getByTestId("template-preview-testimonials")).toBeDefined();
    expect(screen.getByTestId("template-preview-blog")).toBeDefined();
    expect(screen.getByTestId("template-preview-team")).toBeDefined();
    expect(screen.getByTestId("template-preview-footer")).toBeDefined();
  });

  it("미니 썸네일은 각 템플릿 레이아웃을 암시하는 구조를 가져야 한다", () => {
    render(<BlocksSidebar />);

    const heroThumb = screen.getByTestId("template-preview-hero");
    const ctaThumb = screen.getByTestId("template-preview-cta");
    const featuresThumb = screen.getByTestId("template-preview-features");
    const pricingThumb = screen.getByTestId("template-preview-pricing");
    const blogThumb = screen.getByTestId("template-preview-blog");
    const teamThumb = screen.getByTestId("template-preview-team");

    // Hero/CTA: 하나의 메인 영역을 가진 1열 구조
    expect(heroThumb.children.length).toBe(1);
    expect(ctaThumb.children.length).toBe(1);

    // Features/Blog: 3컬럼 레이아웃을 암시하는 3개의 세그먼트
    expect(featuresThumb.children.length).toBe(3);
    expect(blogThumb.children.length).toBe(3);

    // Pricing/Team: 높이가 다른 3개의 바를 가진 3컬럼 카드 레이아웃
    expect(pricingThumb.children.length).toBe(3);
    expect(teamThumb.children.length).toBe(3);
  });

  it("블록 섹션 타이틀을 클릭하면 블록 버튼들을 접고 펼 수 있어야 한다", () => {
    render(<BlocksSidebar />);

    // 초기에는 텍스트 버튼이 보여야 한다.
    expect(screen.getByRole("button", { name: "텍스트" })).toBeDefined();

    const blockToggle = screen.getByRole("button", { name: "블록" });
    fireEvent.click(blockToggle);

    // 접힌 상태에서는 텍스트 버튼이 보이지 않아야 한다.
    expect(screen.queryByRole("button", { name: "텍스트" })).toBeNull();

    // 다시 클릭하면 펼쳐져야 한다.
    fireEvent.click(blockToggle);
    expect(screen.getByRole("button", { name: "텍스트" })).toBeDefined();
  });

  it("폼 요소 섹션 타이틀을 클릭하면 폼 관련 버튼들을 접고 펼 수 있어야 한다", () => {
    render(<BlocksSidebar />);

    // 초기에는 폼 입력 버튼이 보여야 한다.
    expect(screen.getByRole("button", { name: "입력(Input)" })).toBeDefined();

    const formToggle = screen.getByRole("button", { name: "폼 요소" });
    fireEvent.click(formToggle);

    // 접힌 상태에서는 폼 입력 버튼이 보이지 않아야 한다.
    expect(screen.queryByRole("button", { name: "입력(Input)" })).toBeNull();

    // 다시 클릭하면 펼쳐져야 한다.
    fireEvent.click(formToggle);
    expect(screen.getByRole("button", { name: "입력(Input)" })).toBeDefined();
  });

  it("템플릿 섹션 타이틀을 클릭하면 템플릿 카드들을 접고 펼 수 있어야 한다", () => {
    render(<BlocksSidebar />);

    // 초기에는 Hero 템플릿 버튼이 보여야 한다.
    expect(screen.getByRole("button", { name: "Hero 템플릿" })).toBeDefined();

    const templateToggle = screen.getByRole("button", { name: "템플릿" });
    fireEvent.click(templateToggle);

    // 접힌 상태에서는 Hero 템플릿 버튼이 보이지 않아야 한다.
    expect(screen.queryByRole("button", { name: "Hero 템플릿" })).toBeNull();

    // 다시 클릭하면 펼쳐져야 한다.
    fireEvent.click(templateToggle);
    expect(screen.getByRole("button", { name: "Hero 템플릿" })).toBeDefined();
  });
});
