import { describe, it, expect } from "vitest";
import { expectNoPxInStyleParts } from "./styleInvariants";
import {
  normalizeVideoSourceUrl,
  resolveVideoPlatform,
  buildVideoEmbedUrl,
  computeVideoPublicTokens,
  computeVideoEditorTokens,
  computeVideoExportTokens,
} from "@/features/editor/utils/videoHelpers";
import type { VideoBlockProps } from "@/features/editor/state/editorStore";

describe("videoHelpers", () => {
  it("normalizeVideoSourceUrl 은 null/undefined 를 빈 문자열로 만들고 공백을 제거해야 한다", () => {
    expect(normalizeVideoSourceUrl(undefined)).toBe("");
    expect(normalizeVideoSourceUrl(null)).toBe("");
    expect(normalizeVideoSourceUrl("")).toBe("");
    expect(normalizeVideoSourceUrl("  https://example.com/video.mp4  ")).toBe("https://example.com/video.mp4");
  });

  it("resolveVideoPlatform 은 platform 이 auto 일 때 URL 로부터 youtube/vimeo/html5 를 판별해야 한다", () => {
    expect(resolveVideoPlatform("https://www.youtube.com/watch?v=dQw4w9WgXcQ", "auto")).toBe("youtube");
    expect(resolveVideoPlatform("https://youtu.be/dQw4w9WgXcQ", "auto")).toBe("youtube");
    expect(resolveVideoPlatform("https://vimeo.com/123456", "auto")).toBe("vimeo");
    expect(resolveVideoPlatform("/videos/local.mp4", "auto")).toBe("html5");
  });

  it("resolveVideoPlatform 은 platform 이 명시된 경우 해당 값을 우선 사용해야 한다", () => {
    expect(resolveVideoPlatform("https://example.com/video", "youtube")).toBe("youtube");
    expect(resolveVideoPlatform("https://example.com/video", "vimeo")).toBe("vimeo");
    expect(resolveVideoPlatform("https://www.youtube.com/watch?v=dQw4w9WgXcQ", "html5")).toBe("html5");
  });

  it("buildVideoEmbedUrl 은 YouTube URL 을 embed URL 로 변환해야 한다", () => {
    expect(buildVideoEmbedUrl("https://www.youtube.com/watch?v=dQw4w9WgXcQ", "youtube")).toBe(
      "https://www.youtube.com/embed/dQw4w9WgXcQ",
    );
    expect(buildVideoEmbedUrl("https://youtu.be/dQw4w9WgXcQ", "youtube")).toBe(
      "https://www.youtube.com/embed/dQw4w9WgXcQ",
    );
    expect(buildVideoEmbedUrl("https://www.youtube.com/shorts/dQw4w9WgXcQ", "youtube")).toBe(
      "https://www.youtube.com/embed/dQw4w9WgXcQ",
    );
  });

  it("buildVideoEmbedUrl 은 Vimeo URL 에 대해 옵션에 따라 embed URL 또는 원본 URL 을 반환해야 한다", () => {
    const url = "https://vimeo.com/123456";
    expect(buildVideoEmbedUrl(url, "vimeo", { enableVimeoEmbed: true })).toBe(
      "https://player.vimeo.com/video/123456",
    );
    expect(buildVideoEmbedUrl(url, "vimeo", { enableVimeoEmbed: false })).toBe("https://vimeo.com/123456");
    expect(buildVideoEmbedUrl(url, "vimeo")).toBe("https://vimeo.com/123456");
  });

  it("buildVideoEmbedUrl 은 html5 플랫폼에서는 정규화된 원본 URL 을 그대로 반환해야 한다", () => {
    expect(buildVideoEmbedUrl("  /videos/local.mp4  ", "html5")).toBe("/videos/local.mp4");
  });
});

describe("videoHelpers.computeVideoPublicTokens", () => {
  const baseProps: VideoBlockProps = {
    sourceUrl: "/videos/sample.mp4",
    align: "center",
    widthMode: "auto",
    aspectRatio: "16:9",
  };

  it("fixed width / 카드 스타일을 em 단위로 계산해야 한다", () => {
    const tokens = computeVideoPublicTokens({
      ...baseProps,
      align: "left",
      widthMode: "fixed",
      widthPx: 640,
      backgroundColorCustom: "#123456",
      cardPaddingPx: 32,
      borderRadiusPx: 16,
    } as any);

    expect(tokens.justifyClass).toBe("justify-start");
    expect(tokens.wrapperStyle.width).toBe("40em");
    expect(tokens.videoStyle.width).toBe("40em");
    expect(tokens.wrapperStyle.backgroundColor).toBe("#123456");
    expect(tokens.wrapperStyle.padding).toBe("2em");
    expect(tokens.wrapperStyle.borderRadius).toBe("1em");
  });

  it("widthMode 가 full 이면 wrapper/video width 를 100% 로 설정해야 한다", () => {
    const tokens = computeVideoPublicTokens({
      ...baseProps,
      widthMode: "full",
      widthPx: 640,
    } as any);

    expect(tokens.wrapperStyle.width).toBe("100%");
    expect(tokens.videoStyle.width).toBe("100%");
  });

  it("aspectRatio 에 따라 aspectClass 를 설정해야 한다", () => {
    const defaultTokens = computeVideoPublicTokens({
      ...baseProps,
      aspectRatio: "16:9",
    } as any);
    const fourThree = computeVideoPublicTokens({
      ...baseProps,
      aspectRatio: "4:3",
    } as any);
    const oneOne = computeVideoPublicTokens({
      ...baseProps,
      aspectRatio: "1:1",
    } as any);

    expect(defaultTokens.aspectClass).toBe("");
    expect(fourThree.aspectClass).toBe(" pb-video-wrapper--4by3");
    expect(oneOne.aspectClass).toBe(" pb-video-wrapper--1by1");
  });
});

describe("videoHelpers.computeVideoExportTokens", () => {
  const baseProps: VideoBlockProps = {
    sourceUrl: "/videos/sample-export.mp4",
    align: "center",
    widthMode: "auto",
    aspectRatio: "16:9",
  };

  const escapers = { escapeAttr: (value: string) => value };

  it("fixed width / 카드 스타일을 em 단위 스타일 파트로 계산해야 한다", () => {
    const tokens = computeVideoExportTokens(
      {
        ...baseProps,
        align: "left",
        widthMode: "fixed",
        widthPx: 640,
        backgroundColorCustom: "#123456",
        cardPaddingPx: 24,
        borderRadiusPx: 16,
      } as any,
      escapers,
    );

    expect(tokens.aspectClass).toBe("");
    expect(tokens.wrapperStyleParts).toContain("width:40em");
    expect(tokens.videoStyleParts).toContain("width:40em");
    expect(tokens.wrapperStyleParts).toContain("background-color:#123456");
    expect(tokens.wrapperStyleParts).toContain("padding:1.5em");
    expect(tokens.wrapperStyleParts).toContain("border-radius:1em");
    expect(tokens.outerStyleParts).toContain("display:flex");
    expect(tokens.outerStyleParts).toContain("justify-content:flex-start");
  });

  it("Export 비디오 wrapper/video 스타일 파트에는 px 단위 값이 포함되지 않아야 한다", () => {
    const tokens = computeVideoExportTokens(
      {
        ...baseProps,
        align: "left",
        widthMode: "fixed",
        widthPx: 640,
        backgroundColorCustom: "#123456",
        cardPaddingPx: 24,
        borderRadiusPx: 16,
      } as any,
      escapers,
    );

    expectNoPxInStyleParts(tokens.wrapperStyleParts);
    expectNoPxInStyleParts(tokens.videoStyleParts);
  });

  it("widthMode 가 full 이면 width:100% 로 설정하고 align 에 따라 justify-content 를 계산해야 한다", () => {
    const right = computeVideoExportTokens(
      {
        ...baseProps,
        align: "right",
        widthMode: "full",
      } as any,
      escapers,
    );

    expect(right.wrapperStyleParts).toContain("width:100%");
    expect(right.videoStyleParts).toContain("width:100%");
    expect(right.outerStyleParts).toContain("justify-content:flex-end");

    const center = computeVideoExportTokens(
      {
        ...baseProps,
        align: "center",
        widthMode: "auto",
      } as any,
      escapers,
    );

    expect(center.outerStyleParts).toContain("justify-content:center");
  });

  it("aspectRatio 에 따라 aspectClass 를 설정해야 한다", () => {
    const def = computeVideoExportTokens(
      {
        ...baseProps,
        aspectRatio: "16:9",
      } as any,
      escapers,
    );
    const fourThree = computeVideoExportTokens(
      {
        ...baseProps,
        aspectRatio: "4:3",
      } as any,
      escapers,
    );
    const oneOne = computeVideoExportTokens(
      {
        ...baseProps,
        aspectRatio: "1:1",
      } as any,
      escapers,
    );

    expect(def.aspectClass).toBe("");
    expect(fourThree.aspectClass).toBe(" pb-video-wrapper--4by3");
    expect(oneOne.aspectClass).toBe(" pb-video-wrapper--1by1");
  });
});

describe("videoHelpers.computeVideoEditorTokens", () => {
  const baseProps: VideoBlockProps = {
    sourceUrl: "/videos/sample-editor.mp4",
    align: "center",
    widthMode: "auto",
    aspectRatio: "16:9",
  };

  it("fixed width / 카드 스타일을 px 단위로 계산해야 한다", () => {
    const tokens = computeVideoEditorTokens({
      ...baseProps,
      align: "left",
      widthMode: "fixed",
      widthPx: 640,
      backgroundColorCustom: "#123456",
      cardPaddingPx: 24,
      borderRadiusPx: 16,
    } as any);

    expect(tokens.justifyClass).toBe("justify-start");
    expect(tokens.wrapperStyle.width).toBe("640px");
    expect(tokens.videoStyle.width).toBe("640px");
    expect(tokens.wrapperStyle.backgroundColor).toBe("#123456");
    expect(tokens.wrapperStyle.padding).toBe("24px");
    expect(tokens.wrapperStyle.borderRadius).toBe("16px");
  });

  it("widthMode 가 full 이면 wrapper/video width 를 100% 로 설정해야 한다", () => {
    const tokens = computeVideoEditorTokens({
      ...baseProps,
      widthMode: "full",
      widthPx: 640,
    } as any);

    expect(tokens.wrapperStyle.width).toBe("100%");
    expect(tokens.videoStyle.width).toBe("100%");
  });

  it("aspectRatio 에 따라 aspectClass 를 설정해야 한다", () => {
    const defaultTokens = computeVideoEditorTokens({
      ...baseProps,
      aspectRatio: "16:9",
    } as any);
    const fourThree = computeVideoEditorTokens({
      ...baseProps,
      aspectRatio: "4:3",
    } as any);
    const oneOne = computeVideoEditorTokens({
      ...baseProps,
      aspectRatio: "1:1",
    } as any);

    expect(defaultTokens.aspectClass).toBe("");
    expect(fourThree.aspectClass).toBe(" pb-video-wrapper--4by3");
    expect(oneOne.aspectClass).toBe(" pb-video-wrapper--1by1");
  });
});
