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

// 섹션 패널의 숫자 슬라이더/프리셋 제어가 정상적으로 동작하는지 최소 한 번은 검증한다.
describe("SectionPropertiesPanel", () => {
  const baseProps: SectionBlockProps = {
    background: "default",
    paddingY: "md",
    columns: [],
    maxWidthMode: "normal",
    gapX: "md",
  };

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

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

    render(
      <SectionPropertiesPanel
        sectionProps={{
          ...baseProps,
          backgroundColorCustom: "#111111",
        }}
        selectedBlockId="section-bg-1"
        updateBlock={updateBlock}
      />,
    );

    const hexInput = screen.getByLabelText("섹션 배경 색상 HEX 입력");
    fireEvent.change(hexInput, { target: { value: "#112233" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "section-bg-1",
      expect.objectContaining({ backgroundColorCustom: "#112233" }),
    );
  });

  it("가로 위치 프리셋 드롭다운 변경 시 backgroundImagePositionXPercent 가 0/50/100 등으로 설정된다", () => {
    const updateBlock = vi.fn();

    render(
      <SectionPropertiesPanel
        sectionProps={{
          ...baseProps,
          backgroundImagePositionMode: "custom",
          backgroundImagePositionXPercent: 50,
          backgroundImageSrc: "https://example.com/bg.png",
          backgroundImageSourceType: "externalUrl",
        }}
        selectedBlockId="section-xy-x"
        updateBlock={updateBlock}
      />,
    );

    const presetSelect = screen.getByLabelText("배경 이미지 가로 위치 프리셋");
    fireEvent.change(presetSelect, { target: { value: "left" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "section-xy-x",
      expect.objectContaining({ backgroundImagePositionXPercent: 0 }),
    );
  });

  it("세로 위치 프리셋 드롭다운 변경 시 backgroundImagePositionYPercent 가 0/50/100 등으로 설정된다", () => {
    const updateBlock = vi.fn();

    render(
      <SectionPropertiesPanel
        sectionProps={{
          ...baseProps,
          backgroundImagePositionMode: "custom",
          backgroundImagePositionYPercent: 50,
          backgroundImageSrc: "https://example.com/bg.png",
          backgroundImageSourceType: "externalUrl",
        }}
        selectedBlockId="section-xy-y"
        updateBlock={updateBlock}
      />,
    );

    const presetSelect = screen.getByLabelText("배경 이미지 세로 위치 프리셋");
    fireEvent.change(presetSelect, { target: { value: "top" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "section-xy-y",
      expect.objectContaining({ backgroundImagePositionYPercent: 0 }),
    );
  });

  it("위치 모드를 custom 으로 두면 X/Y 퍼센트 슬라이더 변경 시 backgroundImagePositionXPercent/YPercent 가 업데이트된다", () => {
    const updateBlock = vi.fn();

    render(
      <SectionPropertiesPanel
        sectionProps={{
          ...baseProps,
          backgroundImagePositionMode: "custom",
          backgroundImagePositionXPercent: 50,
          backgroundImagePositionYPercent: 50,
          backgroundImageSrc: "https://example.com/bg.png",
          backgroundImageSourceType: "externalUrl",
        }}
        selectedBlockId="section-xy"
        updateBlock={updateBlock}
      />,
    );

    const xSlider = screen.getByLabelText("배경 이미지 가로 위치 슬라이더");
    fireEvent.change(xSlider, { target: { value: "30" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "section-xy",
      expect.objectContaining({
        backgroundImagePositionMode: "custom",
        backgroundImagePositionXPercent: 30,
      }),
    );

    const ySlider = screen.getByLabelText("배경 이미지 세로 위치 슬라이더");
    fireEvent.change(ySlider, { target: { value: "70" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "section-xy",
      expect.objectContaining({
        backgroundImagePositionMode: "custom",
        backgroundImagePositionYPercent: 70,
      }),
    );
  });

  it("세로 패딩 프리셋/슬라이더 변경 시 updateBlock 이 paddingYPx 로 호출된다", () => {
    const updateBlock = vi.fn();
    render(
      <SectionPropertiesPanel
        sectionProps={{ ...baseProps, paddingYPx: 48 }}
        selectedBlockId="section-1"
        updateBlock={updateBlock}
      />,
    );

    const slider = screen.getByLabelText("세로 패딩 슬라이더");
    fireEvent.change(slider, { target: { value: "40" } });

    expect(updateBlock).toHaveBeenCalledWith("section-1", expect.objectContaining({ paddingYPx: 40 }));
  });

  it("배경 이미지 URL 인풋 변경 시 updateBlock 이 backgroundImageSrc/SourceType/AssetId 로 호출된다", () => {
    const updateBlock = vi.fn();

    render(
      <SectionPropertiesPanel
        sectionProps={{ ...baseProps, backgroundImageSrc: "", backgroundImageSourceType: "externalUrl" }}
        selectedBlockId="section-2"
        updateBlock={updateBlock}
      />,
    );

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

    expect(updateBlock).toHaveBeenCalledWith(
      "section-2",
      expect.objectContaining({
        backgroundImageSrc: "https://example.com/bg.png",
        backgroundImageSourceType: "externalUrl",
        backgroundImageAssetId: null,
      }),
    );
  });

  it("배경 이미지 크기 셀렉트 변경 시 updateBlock 이 backgroundImageSize 로 호출된다", () => {
    const updateBlock = vi.fn();

    render(
      <SectionPropertiesPanel
        sectionProps={{
          ...baseProps,
          backgroundImageSize: "cover",
          backgroundImageSrc: "https://example.com/bg.png",
          backgroundImageSourceType: "externalUrl",
        }}
        selectedBlockId="section-3"
        updateBlock={updateBlock}
      />,
    );

    const select = screen.getByLabelText("배경 이미지 크기");
    fireEvent.change(select, { target: { value: "contain" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "section-3",
      expect.objectContaining({ backgroundImageSize: "contain" }),
    );
  });

  it("배경 이미지 위치 셀렉트 변경 시 updateBlock 이 backgroundImagePosition 으로 호출된다", () => {
    const updateBlock = vi.fn();

    render(
      <SectionPropertiesPanel
        sectionProps={{
          ...baseProps,
          backgroundImagePosition: "center",
          backgroundImageSrc: "https://example.com/bg.png",
          backgroundImageSourceType: "externalUrl",
        }}
        selectedBlockId="section-4"
        updateBlock={updateBlock}
      />,
    );

    const select = screen.getByLabelText("배경 이미지 위치");
    fireEvent.change(select, { target: { value: "top" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "section-4",
      expect.objectContaining({ backgroundImagePosition: "top" }),
    );
  });

  it("기본 상태에서는 배경 이미지 소스가 '없음' 이고, '없음' 선택 시 관련 필드가 초기화된다", () => {
    const updateBlock = vi.fn();

    render(
      <SectionPropertiesPanel
        sectionProps={{ ...baseProps }}
        selectedBlockId="section-0"
        updateBlock={updateBlock}
      />,
    );

    const sourceSelect = screen.getByLabelText("배경 이미지 소스") as HTMLSelectElement;
    expect(sourceSelect.value).toBe("none");

    fireEvent.change(sourceSelect, { target: { value: "none" } });

    expect(updateBlock).toHaveBeenCalledWith("section-0", {
      backgroundImageSrc: undefined,
      backgroundImageSourceType: undefined,
      backgroundImageAssetId: null,
    } as any);

    // "없음" 상태에서는 크기/위치/반복 컨트롤이 렌더되지 않아야 한다.
    expect(screen.queryByLabelText("배경 이미지 크기")).toBeNull();
    expect(screen.queryByLabelText("배경 이미지 위치")).toBeNull();
    expect(screen.queryByLabelText("배경 이미지 반복")).toBeNull();
  });

  it("배경 이미지 반복 셀렉트 변경 시 updateBlock 이 backgroundImageRepeat 로 호출된다", () => {
    const updateBlock = vi.fn();

    render(
      <SectionPropertiesPanel
        sectionProps={{
          ...baseProps,
          backgroundImageRepeat: "no-repeat",
          backgroundImageSrc: "https://example.com/bg.png",
          backgroundImageSourceType: "externalUrl",
        }}
        selectedBlockId="section-6"
        updateBlock={updateBlock}
      />,
    );

    const repeatSelect = screen.getByLabelText("배경 이미지 반복");
    fireEvent.change(repeatSelect, { target: { value: "repeat-x" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "section-6",
      expect.objectContaining({ backgroundImageRepeat: "repeat-x" }),
    );
  });

  it("배경 이미지 소스 셀렉트 변경 시 updateBlock 이 backgroundImageSourceType/backgroundImageAssetId 로 호출된다", () => {
    const updateBlock = vi.fn();

    render(
      <SectionPropertiesPanel
        sectionProps={{
          ...baseProps,
          backgroundImageSrc: "/api/image/asset-1",
          backgroundImageSourceType: "asset",
          backgroundImageAssetId: "asset-1",
        }}
        selectedBlockId="section-5"
        updateBlock={updateBlock}
      />,
    );

    const sourceSelect = screen.getByLabelText("배경 이미지 소스") as HTMLSelectElement;
    expect(sourceSelect.value).toBe("upload");

    fireEvent.change(sourceSelect, { target: { value: "url" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "section-5",
      expect.objectContaining({
        backgroundImageSourceType: "externalUrl",
        backgroundImageAssetId: null,
      }),
    );
  });

  it("배경 비디오 URL 인풋 변경 시 updateBlock 이 backgroundVideoSrc/backgroundVideoSourceType/backgroundVideoAssetId 로 호출된다", () => {
    const updateBlock = vi.fn();

    render(
      <SectionPropertiesPanel
        sectionProps={{
          ...baseProps,
          backgroundVideoSrc: "",
          backgroundVideoSourceType: "externalUrl",
        }}
        selectedBlockId="section-video-1"
        updateBlock={updateBlock}
      />,
    );

    const urlInput = screen.getByLabelText("배경 비디오 URL");
    fireEvent.change(urlInput, { target: { value: "https://example.com/bg-video.mp4" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "section-video-1",
      expect.objectContaining({
        backgroundVideoSrc: "https://example.com/bg-video.mp4",
        backgroundVideoSourceType: "externalUrl",
        backgroundVideoAssetId: null,
      }),
    );
  });

  it("배경 비디오 소스 셀렉트 변경 시 updateBlock 이 backgroundVideoSourceType/backgroundVideoAssetId 로 호출된다", () => {
    const updateBlock = vi.fn();

    render(
      <SectionPropertiesPanel
        sectionProps={{
          ...baseProps,
          backgroundVideoSrc: "/api/video/asset-video-1",
          backgroundVideoSourceType: "asset",
          backgroundVideoAssetId: "asset-video-1",
        }}
        selectedBlockId="section-video-2"
        updateBlock={updateBlock}
      />,
    );

    const sourceSelect = screen.getByLabelText("배경 비디오 소스") as HTMLSelectElement;
    expect(sourceSelect.value).toBe("upload");

    fireEvent.change(sourceSelect, { target: { value: "url" } });

    expect(updateBlock).toHaveBeenCalledWith(
      "section-video-2",
      expect.objectContaining({
        backgroundVideoSourceType: "externalUrl",
        backgroundVideoAssetId: null,
      }),
    );
  });

  it("SectionPropertiesPanel 배경 이미지/비디오 소스 및 URL 인풋은 라이트/다크 듀얼 테마 크롬을 사용해야 한다", () => {
    const updateBlock = vi.fn();

    render(
      <SectionPropertiesPanel
        sectionProps={{
          ...baseProps,
          backgroundImageSrc: "https://example.com/bg.png",
          backgroundImageSourceType: "externalUrl",
          backgroundVideoSrc: "https://example.com/bg-video.mp4",
          backgroundVideoSourceType: "externalUrl",
        } as any}
        selectedBlockId="section-theme-1"
        updateBlock={updateBlock}
      />,
    );

    const bgImageSourceSelect = screen.getByLabelText("배경 이미지 소스") as HTMLSelectElement;
    const bgImageSourceClass = bgImageSourceSelect.getAttribute("class") ?? "";
    expect(bgImageSourceClass).toContain("bg-white");
    expect(bgImageSourceClass).toContain("text-slate-900");
    expect(bgImageSourceClass).toContain("border-slate-300");
    expect(bgImageSourceClass).toContain("dark:bg-slate-900");
    expect(bgImageSourceClass).toContain("dark:text-slate-100");
    expect(bgImageSourceClass).toContain("dark:border-slate-700");

    const bgImageUrlInput = screen.getByLabelText("배경 이미지 URL") as HTMLInputElement;
    const bgImageUrlClass = bgImageUrlInput.getAttribute("class") ?? "";
    expect(bgImageUrlClass).toContain("bg-white");
    expect(bgImageUrlClass).toContain("text-slate-900");
    expect(bgImageUrlClass).toContain("border-slate-300");
    expect(bgImageUrlClass).toContain("dark:bg-slate-900");
    expect(bgImageUrlClass).toContain("dark:text-slate-100");
    expect(bgImageUrlClass).toContain("dark:border-slate-700");

    const bgVideoUrlInput = screen.getByLabelText("배경 비디오 URL") as HTMLInputElement;
    const bgVideoUrlClass = bgVideoUrlInput.getAttribute("class") ?? "";
    expect(bgVideoUrlClass).toContain("bg-white");
    expect(bgVideoUrlClass).toContain("text-slate-900");
    expect(bgVideoUrlClass).toContain("border-slate-300");
    expect(bgVideoUrlClass).toContain("dark:bg-slate-900");
    expect(bgVideoUrlClass).toContain("dark:text-slate-100");
    expect(bgVideoUrlClass).toContain("dark:border-slate-700");
  });

	it("섹션 레이아웃 및 배경 이미지 레이아웃 셀렉트들은 라이트/다크 듀얼 테마 크롬을 사용해야 한다", () => {
		const updateBlock = vi.fn();

		render(
			<SectionPropertiesPanel
				sectionProps={{
					...baseProps,
					columns: [
						{ id: "col_1", span: 6 },
						{ id: "col_2", span: 6 },
					],
					alignItems: "top",
					backgroundImageSrc: "https://example.com/bg.png",
					backgroundImageSourceType: "externalUrl",
					backgroundImagePositionMode: "preset",
					backgroundImageSize: "cover",
					backgroundImagePosition: "center",
					backgroundImageRepeat: "no-repeat",
				} as any}
				selectedBlockId="section-theme-layout-1"
				updateBlock={updateBlock}
			/>,
		);

		const columnLayoutSelect = screen.getByLabelText("섹션 컬럼 레이아웃") as HTMLSelectElement;
		const alignItemsSelect = screen.getByLabelText("섹션 컬럼 세로 정렬") as HTMLSelectElement;
		const positionModeSelect = screen.getByLabelText("배경 이미지 위치 모드") as HTMLSelectElement;
		const sizeSelect = screen.getByLabelText("배경 이미지 크기") as HTMLSelectElement;
		const positionSelect = screen.getByLabelText("배경 이미지 위치") as HTMLSelectElement;
		const repeatSelect = screen.getByLabelText("배경 이미지 반복") as HTMLSelectElement;

		const assertDualTheme = (el: HTMLElement) => {
			const className = el.getAttribute("class") ?? "";
			expect(className).toContain("bg-white");
			expect(className).toContain("text-slate-900");
			expect(className).toContain("border-slate-300");
			expect(className).toContain("dark:bg-slate-900");
			expect(className).toContain("dark:text-slate-100");
			expect(className).toContain("dark:border-slate-700");
		};

		assertDualTheme(columnLayoutSelect);
		assertDualTheme(alignItemsSelect);
		assertDualTheme(positionModeSelect);
		assertDualTheme(sizeSelect);
		assertDualTheme(positionSelect);
		assertDualTheme(repeatSelect);
	});
});
