import { describe, it, expect, vi, afterEach } from "vitest";
import { render, screen, fireEvent, cleanup } from "@testing-library/react";
import { ButtonPropertiesPanel } from "@/app/editor/panels/ButtonPropertiesPanel";
import type { ButtonBlockProps } from "@/features/editor/state/editorStore";

// ButtonPropertiesPanel 컨트롤 TDD
// - 색상 HEX 인풋 및 너비 모드 셀렉트가 updateBlock 을 올바르게 호출하는지 검증한다.

describe("ButtonPropertiesPanel", () => {
  const baseProps: ButtonBlockProps = {
    label: "버튼",
    href: "#",
    align: "left",
    size: "md",
    variant: "solid",
    colorPalette: "primary",
  };

  afterEach(() => {
    cleanup();
  });

  it("텍스트 색상 HEX 인풋 변경 시 updateBlock 이 textColorCustom 으로 호출되어야 한다", () => {
    const updateBlock = vi.fn();

    render(
      <ButtonPropertiesPanel
        buttonProps={{ ...baseProps, textColorCustom: "#ffffff" }}
        selectedBlockId="btn-1"
        updateBlock={updateBlock}
      />,
    );

    const hexInput = screen.getByLabelText("버튼 텍스트 색상 HEX");
    fireEvent.change(hexInput, { target: { value: "#112233" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "btn-1",
      expect.objectContaining({ textColorCustom: "#112233" }),
    );
  });

  it("채움 색상 HEX 인풋 변경 시 updateBlock 이 fillColorCustom 으로 호출되어야 한다", () => {
    const updateBlock = vi.fn();

    render(
      <ButtonPropertiesPanel
        buttonProps={{ ...baseProps, fillColorCustom: "#000000" }}
        selectedBlockId="btn-2"
        updateBlock={updateBlock}
      />,
    );

    const hexInput = screen.getByLabelText("버튼 채움 색상 HEX");
    fireEvent.change(hexInput, { target: { value: "#445566" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "btn-2",
      expect.objectContaining({ fillColorCustom: "#445566" }),
    );
  });

  it("외곽선 색상 HEX 인풋 변경 시 updateBlock 이 strokeColorCustom 으로 호출되어야 한다", () => {
    const updateBlock = vi.fn();

    render(
      <ButtonPropertiesPanel
        buttonProps={{ ...baseProps, strokeColorCustom: "#000000" }}
        selectedBlockId="btn-3"
        updateBlock={updateBlock}
      />,
    );

    const hexInput = screen.getByLabelText("버튼 외곽선 색상 HEX");
    fireEvent.change(hexInput, { target: { value: "#778899" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "btn-3",
      expect.objectContaining({ strokeColorCustom: "#778899" }),
    );
  });

  it("버튼 너비 모드 셀렉트 변경 시 updateBlock 이 widthMode 로 호출되어야 한다", () => {
    const updateBlock = vi.fn();

    render(
      <ButtonPropertiesPanel
        buttonProps={{ ...baseProps, widthMode: "auto", fullWidth: false }}
        selectedBlockId="btn-4"
        updateBlock={updateBlock}
      />,
    );

    const select = screen.getByLabelText("버튼 너비 모드");
    fireEvent.change(select, { target: { value: "fixed" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "btn-4",
      expect.objectContaining({ widthMode: "fixed" }),
    );
  });

  it("버튼 이미지 URL 인풋 변경 시 updateBlock 이 imageSrc 와 imageSourceType(externalUrl) 으로 호출되어야 한다", () => {
    const updateBlock = vi.fn();

    render(
      <ButtonPropertiesPanel
        buttonProps={{
          ...baseProps,
          imageSrc: "https://example.com/old.png",
          imageSourceType: "externalUrl",
        } as any}
        selectedBlockId="btn-img-url"
        updateBlock={updateBlock}
      />,
    );

    const urlInput = screen.getByLabelText("버튼 이미지 URL");
    fireEvent.change(urlInput, { target: { value: "https://example.com/new.png" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "btn-img-url",
      expect.objectContaining({
        imageSrc: "https://example.com/new.png",
        imageSourceType: "externalUrl",
      }),
    );
  });

  it("버튼 이미지 위치 셀렉트 변경 시 updateBlock 이 imagePlacement 로 호출되어야 한다", () => {
    const updateBlock = vi.fn();

    render(
      <ButtonPropertiesPanel
        buttonProps={{
          ...baseProps,
          imagePlacement: "left",
          imageSrc: "https://example.com/icon.png",
          imageSourceType: "externalUrl",
        } as any}
        selectedBlockId="btn-img-pos"
        updateBlock={updateBlock}
      />,
    );

    const select = screen.getByLabelText("버튼 이미지 위치");
    fireEvent.change(select, { target: { value: "right" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "btn-img-pos",
      expect.objectContaining({ imagePlacement: "right" }),
    );
  });

  it("버튼 이미지 소스 셀렉트에서 URL/업로드를 전환할 수 있어야 한다", () => {
    const updateBlock = vi.fn();

    render(
      <ButtonPropertiesPanel
        buttonProps={{
          ...baseProps,
          imageSrc: "/api/image/test-id",
          imageSourceType: "asset",
        } as any}
        selectedBlockId="btn-img-source"
        updateBlock={updateBlock}
      />,
    );

    const select = screen.getByLabelText("버튼 이미지 소스");
    // 업로드 → URL 로 전환
    fireEvent.change(select, { target: { value: "url" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "btn-img-source",
      expect.objectContaining({
        imageSourceType: "externalUrl",
        imageAssetId: null,
      }),
    );
  });
});
