import { describe, it, expect } from "vitest";
import { expectNoPxInStyleObject, expectNoPxInStyleParts } from "./styleInvariants";
import {
  computeSectionExportTokens,
  computeSectionPublicTokens,
  computeSectionEditorTokens,
} from "@/features/editor/utils/sectionHelpers";
import type { SectionBlockProps } from "@/features/editor/state/editorStore";

const baseProps: SectionBlockProps = {
  background: "default",
  paddingY: "md",
  columns: [{ id: "sec_col_1", span: 12 }],
  maxWidthMode: "normal",
  gapX: "md",
};

describe("sectionHelpers.computeSectionExportTokens", () => {
  it("기본 섹션은 pb-section / pb-section-bg-default / pb-section-py-md 를 포함해야 한다", () => {
    const tokens = computeSectionExportTokens(baseProps);

    expect(tokens.sectionClasses).toContain("pb-section");
    expect(tokens.sectionClasses).toContain("pb-section-bg-default");
    expect(tokens.sectionClasses).toContain("pb-section-py-md");
    expect(tokens.sectionStyleParts.length).toBe(0);
    expect(tokens.backgroundVideoHtml).toBe("");
  });

  it("background=muted/primary 와 paddingY=sm/lg 는 각각 대응하는 pb-section-bg-*/pb-section-py-* 클래스로 매핑되어야 한다", () => {
    const muted = computeSectionExportTokens({ ...baseProps, background: "muted" });
    const primary = computeSectionExportTokens({ ...baseProps, background: "primary" });
    const sm = computeSectionExportTokens({ ...baseProps, paddingY: "sm" });
    const lg = computeSectionExportTokens({ ...baseProps, paddingY: "lg" });

    expect(muted.sectionClasses).toContain("pb-section-bg-muted");
    expect(primary.sectionClasses).toContain("pb-section-bg-primary");
    expect(sm.sectionClasses).toContain("pb-section-py-sm");
    expect(lg.sectionClasses).toContain("pb-section-py-lg");
  });

  it("backgroundColorCustom 이 있으면 background-color 스타일을 추가해야 한다", () => {
    const tokens = computeSectionExportTokens({
      ...baseProps,
      backgroundColorCustom: "#123456",
    });

    expect(tokens.sectionStyleParts).toContain("background-color:#123456");
  });

  it("backgroundImage 관련 옵션이 있으면 background-image/size/position/repeat 스타일을 추가해야 한다", () => {
    const tokens = computeSectionExportTokens({
      ...baseProps,
      backgroundImageSrc: "https://example.com/bg.png",
      backgroundImageSize: "cover",
      backgroundImagePositionMode: "preset",
      backgroundImagePosition: "top",
      backgroundImageRepeat: "repeat-x",
    });

    expect(tokens.sectionStyleParts).toContain("background-image:url(https://example.com/bg.png)");
    expect(tokens.sectionStyleParts).toContain("background-size:cover");
    expect(tokens.sectionStyleParts).toContain("background-position:center top");
    expect(tokens.sectionStyleParts).toContain("background-repeat:repeat-x");
  });

  it("배경 비디오가 있으면 backgroundVideoHtml 과 position/overflow 스타일을 추가해야 한다", () => {
    const tokens = computeSectionExportTokens({
      ...baseProps,
      backgroundVideoSrc: "https://example.com/bg.mp4",
    });

    expect(tokens.backgroundVideoHtml).toContain("pb-section-bg-video");
    expect(tokens.backgroundVideoHtml).toContain("https://example.com/bg.mp4");
    expect(tokens.sectionStyleParts).toContain("position:relative");
    expect(tokens.sectionStyleParts).toContain("overflow:hidden");
  });

  it("Export 섹션 sectionStyleParts 에는 px 단위 값이 포함되지 않아야 한다", () => {
    const tokens = computeSectionExportTokens({
      ...baseProps,
      backgroundColorCustom: "#123456",
      backgroundImageSrc: "https://example.com/bg.png",
      backgroundImageSize: "cover",
      backgroundImagePositionMode: "preset",
      backgroundImagePosition: "top",
      backgroundImageRepeat: "repeat-x",
      backgroundVideoSrc: "https://example.com/bg.mp4",
    } as SectionBlockProps);

    expectNoPxInStyleParts(tokens.sectionStyleParts);
  });
});

describe("sectionHelpers.computeSectionPublicTokens", () => {
  it("배경색 / paddingYPx / maxWidthPx / gapXPx 를 em 단위 스타일로 계산해야 한다", () => {
    const tokens = computeSectionPublicTokens({
      ...baseProps,
      backgroundColorCustom: "  #123456  ",
      paddingYPx: 32,
      maxWidthPx: 800,
      gapXPx: 24,
    });

    expect(tokens.sectionStyle.backgroundColor).toBe("#123456");
    expect(tokens.sectionStyle.paddingTop).toBe("2em");
    expect(tokens.sectionStyle.paddingBottom).toBe("2em");
    expect(tokens.innerWrapperStyle.maxWidth).toBe("50em");
    expect(tokens.columnsContainerStyle.columnGap).toBe("1.5em");

    // 퍼블릭 섹션 토큰 스타일에는 px 단위 값이 포함되지 않아야 한다.
    expectNoPxInStyleObject(tokens.sectionStyle);
    expectNoPxInStyleObject(tokens.innerWrapperStyle);
    expectNoPxInStyleObject(tokens.columnsContainerStyle);
  });

  it("backgroundImage* 와 backgroundVideoSrc 를 올바르게 반영해야 한다", () => {
    const tokens = computeSectionPublicTokens({
      ...baseProps,
      backgroundImageSrc: "https://example.com/bg.png",
      backgroundImageSize: "cover",
      backgroundImagePositionMode: "preset",
      backgroundImagePosition: "top",
      backgroundImageRepeat: "repeat-x",
      backgroundVideoSrc: "  https://example.com/bg.mp4  ",
    } as any);

    expect(tokens.sectionStyle.backgroundImage).toBe("url(https://example.com/bg.png)");
    expect(tokens.sectionStyle.backgroundSize).toBe("cover");
    expect(tokens.sectionStyle.backgroundPosition).toBe("center top");
    expect(tokens.sectionStyle.backgroundRepeat).toBe("repeat-x");
    expect(tokens.hasBackgroundVideo).toBe(true);
    expect(tokens.backgroundVideoSrc).toBe("https://example.com/bg.mp4");
    expect(tokens.sectionStyle.position).toBe("relative");
    expect(tokens.sectionStyle.overflow).toBe("hidden");
  });
});

describe("sectionHelpers.computeSectionEditorTokens", () => {
  it("backgroundColorCustom / paddingYPx / maxWidthPx / gapXPx 가 px 단위 스타일로 계산되어야 한다", () => {
    const tokens = computeSectionEditorTokens({
      ...baseProps,
      backgroundColorCustom: "#123456",
      paddingYPx: 80,
      maxWidthPx: 960,
      gapXPx: 32,
      alignItems: "center",
    } as any);

    expect(tokens.wrapperStyle.backgroundColor).toBe("#123456");
    expect(tokens.wrapperStyle.paddingTop).toBe("80px");
    expect(tokens.wrapperStyle.paddingBottom).toBe("80px");
    expect(tokens.innerWrapperStyle.maxWidth).toBe("960px");
    expect(tokens.columnsContainerStyle.columnGap).toBe("32px");
    expect(tokens.alignItemsClass).toBe("items-center");
  });

  it("background 및 paddingY 값에 따라 bgClass/pyClass 를 계산해야 한다", () => {
    const muted = computeSectionEditorTokens({ ...baseProps, background: "muted" } as any);
    const primary = computeSectionEditorTokens({ ...baseProps, background: "primary" } as any);
    const sm = computeSectionEditorTokens({ ...baseProps, paddingY: "sm" } as any);
    const lg = computeSectionEditorTokens({ ...baseProps, paddingY: "lg" } as any);

    expect(muted.bgClass).toContain("bg-slate-950/40");
    expect(primary.bgClass).toContain("bg-sky-950/40");
    expect(primary.bgClass).toContain("border-sky-900/60");
    expect(sm.pyClass).toBe("py-4");
    expect(lg.pyClass).toBe("py-10");
  });

  it("backgroundImage* 옵션이 있으면 wrapperStyle 에 backgroundImage/Size/Position/Repeat 이 반영되어야 한다", () => {
    const tokens = computeSectionEditorTokens({
      ...baseProps,
      backgroundImageSrc: "https://example.com/bg.png",
      backgroundImageSize: "cover",
      backgroundImagePositionMode: "preset",
      backgroundImagePosition: "top",
      backgroundImageRepeat: "repeat-x",
    } as any);

    expect(tokens.wrapperStyle.backgroundImage).toBe("url(https://example.com/bg.png)");
    expect(tokens.wrapperStyle.backgroundSize).toBe("cover");
    expect(tokens.wrapperStyle.backgroundPosition).toBe("center top");
    expect(tokens.wrapperStyle.backgroundRepeat).toBe("repeat-x");
  });

  it("backgroundImagePositionMode 가 custom 이고 X/Y 퍼센트가 설정되면 background-position 은 'X% Y%' 로 설정되어야 한다", () => {
    const tokens = computeSectionEditorTokens({
      ...baseProps,
      backgroundImageSrc: "https://example.com/bg-xy.png",
      backgroundImageSize: "cover",
      backgroundImagePositionMode: "custom",
      backgroundImagePositionXPercent: 30,
      backgroundImagePositionYPercent: 70,
    } as any);

    expect(tokens.wrapperStyle.backgroundImage).toBe("url(https://example.com/bg-xy.png)");
    expect(tokens.wrapperStyle.backgroundPosition).toBe("30% 70%");
  });

  it("backgroundVideoSrc 가 있으면 hasBackgroundVideo=true, backgroundVideoSrc 와 position/overflow 스타일이 설정되어야 한다", () => {
    const tokens = computeSectionEditorTokens({
      ...baseProps,
      backgroundVideoSrc: "  https://example.com/bg.mp4  ",
    } as any);

    expect(tokens.hasBackgroundVideo).toBe(true);
    expect(tokens.backgroundVideoSrc).toBe("https://example.com/bg.mp4");
    expect(tokens.wrapperStyle.position).toBe("relative");
    expect(tokens.wrapperStyle.overflow).toBe("hidden");
  });
});
