import { describe, it, expect } from "vitest";
import { expectNoPxInStyleParts } from "./styleInvariants";
import {
  computeButtonPbTokens,
  computeButtonPublicTokens,
  computeButtonEditorTokens,
} from "@/features/editor/utils/buttonHelpers";
import type { ButtonBlockProps } from "@/features/editor/state/editorStore";

const baseProps = {
  align: "left" as const,
  size: "md" as const,
  variant: "solid" as const,
  colorPalette: "primary" as const,
};

describe("buttonHelpers.computeButtonPbTokens", () => {
  it("기본 버튼은 pb-text-left / pb-btn-size-md / pb-btn-variant-solid-primary / pb-btn-radius-md 를 포함해야 한다", () => {
    const tokens = computeButtonPbTokens(baseProps);

    expect(tokens.alignClass).toBe("pb-text-left");
    expect(tokens.sizeClass).toBe("pb-btn-size-md");
    expect(tokens.variantClass).toBe("pb-btn-variant-solid-primary");
    expect(tokens.radiusClass).toBe("pb-btn-radius-md");
    expect(tokens.inlineStyles.length).toBe(0);
  });

  it("정렬/사이즈/팔레트/둥글기 스케일은 pb 토큰으로 올바르게 매핑되어야 한다", () => {
    const tokens = computeButtonPbTokens({
      align: "center",
      size: "lg",
      variant: "outline",
      colorPalette: "danger",
      borderRadius: "full",
    });

    expect(tokens.alignClass).toBe("pb-text-center");
    expect(tokens.sizeClass).toBe("pb-btn-size-lg");
    expect(tokens.variantClass).toBe("pb-btn-variant-outline-danger");
    expect(tokens.radiusClass).toBe("pb-btn-radius-full");
  });

  it("widthMode=fixed, widthPx, paddingX/paddingY, fill/stroke/text 색상은 inlineStyles 에 포함되어야 한다", () => {
    const tokens = computeButtonPbTokens({
      align: "right",
      size: "sm",
      widthMode: "fixed",
      widthPx: 200,
      paddingX: 16,
      paddingY: 8,
      fillColorCustom: "#111111",
      strokeColorCustom: "#222222",
      textColorCustom: "#ffffff",
    });

    expect(tokens.alignClass).toBe("pb-text-right");
    expect(tokens.inlineStyles).toContain("width:12.5em");
    expect(tokens.inlineStyles).toContain("padding-left:1em");
    expect(tokens.inlineStyles).toContain("padding-right:1em");
    expect(tokens.inlineStyles).toContain("padding-top:0.5em");
    expect(tokens.inlineStyles).toContain("padding-bottom:0.5em");
    expect(tokens.inlineStyles).toContain("background-color:#111111");
    expect(tokens.inlineStyles).toContain("border-color:#222222");
    expect(tokens.inlineStyles).toContain("color:#ffffff");
  });

  it("Button Pb inlineStyles 에는 px 단위 값이 포함되지 않아야 한다", () => {
    const tokens = computeButtonPbTokens({
      align: "right",
      size: "sm",
      widthMode: "fixed",
      widthPx: 200,
      paddingX: 16,
      paddingY: 8,
      fillColorCustom: "#111111",
      strokeColorCustom: "#222222",
      textColorCustom: "#ffffff",
    });

    expectNoPxInStyleParts(tokens.inlineStyles);
  });
});

describe("buttonHelpers.computeButtonPublicTokens", () => {
  it("색상 커스텀 값은 backgroundColor/borderColor/borderWidth/borderStyle/color 에 반영되어야 한다", () => {
    const tokens = computeButtonPublicTokens({
      label: "컬러 버튼",
      href: "#",
      align: "center",
      fillColorCustom: "#123456",
      strokeColorCustom: "#ff0000",
      textColorCustom: "#00ff00",
    } as ButtonBlockProps);

    expect(tokens.alignClass).toBe("text-center");
    expect(tokens.styleOverrides.backgroundColor).toBe("#123456");
    expect(tokens.styleOverrides.borderColor).toBe("#ff0000");
    expect(tokens.styleOverrides.borderWidth).toBe("1px");
    expect(tokens.styleOverrides.borderStyle).toBe("solid");
    expect(tokens.styleOverrides.color).toBe("#00ff00");
  });

  it("widthMode=fixed 인 경우 widthPx/paddingX/paddingY 는 em 단위로 변환되어야 한다", () => {
    const tokens = computeButtonPublicTokens({
      label: "레이아웃 버튼",
      href: "#",
      align: "left",
      widthMode: "fixed",
      widthPx: 320,
      paddingX: 16,
      paddingY: 8,
    } as ButtonBlockProps);

    expect(tokens.alignClass).toBe("text-left");
    expect(tokens.styleOverrides.width).toBe("20em");
    expect(tokens.styleOverrides.paddingInline).toBe("1em");
    expect(tokens.styleOverrides.paddingBlock).toBe("0.5em");
  });

  it("borderRadius 토큰은 em 단위 둥글기 또는 9999px 로 변환되어야 한다", () => {
    const lgTokens = computeButtonPublicTokens({
      label: "둥근 버튼",
      href: "#",
      borderRadius: "lg",
    } as ButtonBlockProps);

    expect(lgTokens.styleOverrides.borderRadius).toBe("0.75em");

    const fullTokens = computeButtonPublicTokens({
      label: "풀 둥근 버튼",
      href: "#",
      borderRadius: "full",
    } as ButtonBlockProps);

    expect(fullTokens.styleOverrides.borderRadius).toBe("9999px");
  });
});

describe("buttonHelpers.computeButtonEditorTokens", () => {
  it("fullWidth 나 widthMode 에 따라 wrapperWidthClass 와 버튼 스타일이 계산되어야 한다", () => {
    const tokens = computeButtonEditorTokens({
      label: "테스트 버튼",
      href: "#",
      align: "center",
      size: "lg",
      variant: "outline",
      colorPalette: "success",
      borderRadius: "full",
      fullWidth: true,
      fontSizeCustom: "18px",
      lineHeightCustom: "1.8",
      letterSpacingCustom: "0.1em",
      fillColorCustom: "#123456",
      strokeColorCustom: "#654321",
      textColorCustom: "#ff0000",
      paddingX: 16,
      paddingY: 10,
    } as ButtonBlockProps);

    // fullWidth=true 이므로 wrapperWidthClass 는 w-full 이어야 한다.
    expect(tokens.wrapperWidthClass).toBe("w-full");

    // 버튼 스타일에 색상/패딩/타이포 값이 그대로 반영되어야 한다.
    expect(tokens.buttonStyle.backgroundColor).toBe("#123456");
    expect(tokens.buttonStyle.borderColor).toBe("#654321");
    expect(tokens.buttonStyle.color).toBe("#ff0000");
    expect(tokens.buttonStyle.paddingInline).toBe("16px");
    expect(tokens.buttonStyle.paddingBlock).toBe("10px");
    expect(tokens.buttonStyle.fontSize).toBe("18px");
    expect(tokens.buttonStyle.lineHeight).toBe("1.8");
    expect(tokens.buttonStyle.letterSpacing).toBe("0.1em");
  });

  it("widthMode=fixed 인 경우 widthPx 는 버튼 width 스타일에 반영되고 wrapperWidthClass 는 inline-block 이어야 한다", () => {
    const tokens = computeButtonEditorTokens({
      label: "고정 너비 버튼",
      href: "#",
      align: "left",
      size: "md",
      variant: "solid",
      colorPalette: "primary",
      borderRadius: "md",
      fullWidth: false,
      widthMode: "fixed",
      widthPx: 200,
    } as ButtonBlockProps);

    expect(tokens.wrapperWidthClass).toBe("inline-block");
    expect(tokens.buttonStyle.width).toBe("200px");
  });
});
