"use client";

import { useState } from "react";
import type { Block, ButtonBlockProps, FormBlockProps, ListBlockProps, SectionBlockProps, TextBlockProps, VideoBlockProps } from "@/features/editor/state/editorStore";
import { ButtonPropertiesPanel } from "./ButtonPropertiesPanel";
import { TextPropertiesPanel } from "./TextPropertiesPanel";
import { ListPropertiesPanel } from "./ListPropertiesPanel";
import { DividerPropertiesPanel } from "./DividerPropertiesPanel";
import { ImagePropertiesPanel } from "./ImagePropertiesPanel";
import { SectionPropertiesPanel } from "./SectionPropertiesPanel";
import { VideoPropertiesPanel } from "./VideoPropertiesPanel";
import { FormInputPropertiesPanel } from "../forms/FormInputPropertiesPanel";
import { FormSelectPropertiesPanel } from "../forms/FormSelectPropertiesPanel";
import { FormCheckboxPropertiesPanel } from "../forms/FormCheckboxPropertiesPanel";
import { FormRadioPropertiesPanel } from "../forms/FormRadioPropertiesPanel";
import { FormControllerPanel } from "../forms/FormControllerPanel";
import { ProjectPropertiesPanel } from "./ProjectPropertiesPanel";
import { Trash2, Copy, SlidersHorizontal, HelpCircle } from "lucide-react";

type BlockHelpProperty = {
  label: string;
  description: string;
};

type BlockHelpContent = {
  title: string;
  description: string;
  properties?: BlockHelpProperty[];
};

interface PropertiesSidebarProps {
  blocks: Block[];
  selectedBlockId: string | null;
  selectedListItemId: string | null;
  updateBlock: (id: string, partial: any) => void;
  removeBlock: (id: string) => void;
  duplicateBlock: (id: string) => void;
  // 텍스트 속성 패널에서 사용하는 인라인 편집 상태를 그대로 전달한다.
  editingBlockId: string | null;
  setEditingText: (value: string) => void;
  onMoveSelectedItemUp: (blockId: string) => void;
  onMoveSelectedItemDown: (blockId: string) => void;
  onIndentSelectedItem: (blockId: string) => void;
  onOutdentSelectedItem: (blockId: string) => void;
}

// 우측 속성 패널을 분리한 컴포넌트
export function PropertiesSidebar(props: PropertiesSidebarProps) {
  const {
    blocks,
    selectedBlockId,
    selectedListItemId,
    updateBlock,
    removeBlock,
    duplicateBlock,
    editingBlockId,
    setEditingText,
    onMoveSelectedItemUp,
    onMoveSelectedItemDown,
    onIndentSelectedItem,
    onOutdentSelectedItem,
  } = props;

  const [helpOpen, setHelpOpen] = useState(false);

  const getHelpContentForSelectedBlock = (): BlockHelpContent | null => {
    if (!selectedBlockId) return null;
    const selectedBlock = blocks.find((b) => b.id === selectedBlockId);
    if (!selectedBlock) return null;

    switch (selectedBlock.type) {
      case "text":
        return {
          title: "텍스트 블록 튜토리얼",
          description:
            "제목과 본문 텍스트를 입력할 때 사용하는 기본 블록입니다.\n\n좌측 패널에서 텍스트를 추가한 뒤, 캔버스에서 텍스트를 더블클릭하거나 속성 패널에서 내용을 수정해 보세요. 정렬, 크기, 색상 등을 조절해 다양한 스타일의 텍스트를 만들 수 있습니다.",
          properties: [
            {
              label: "선택한 텍스트 블록 내용",
              description:
                "이 블록에 실제로 표시될 문장을 입력하는 영역입니다. 캔버스에서 텍스트를 더블클릭했을 때와 동일한 내용이며, 여러 줄을 입력하면 줄바꿈이 그대로 반영됩니다.",
            },
            {
              label: "정렬",
              description:
                "텍스트를 왼쪽/가운데/오른쪽 중 어디에 맞출지 결정합니다. 일반 본문은 왼쪽, Hero 제목이나 짧은 강조 문구는 가운데 정렬을 추천합니다.",
            },
            {
              label: "텍스트 스타일 (밑줄/가운데줄/이탤릭)",
              description:
                "밑줄은 링크처럼 보이게 하거나 특정 단어를 강조할 때, 가운데줄은 할인 전 가격처럼 취소선을 표현할 때, 이탤릭은 인용구나 제품명 등 살짝 톤을 바꾸고 싶을 때 사용합니다.",
            },
            {
              label: "글자 크기",
              description:
                "텍스트의 폰트 크기를 px 단위로 조절합니다. 프리셋(XS~3XL)으로 대략적인 크기를 고른 뒤, 슬라이더/숫자 입력으로 세밀하게 조정할 수 있습니다.",
            },
            {
              label: "글자 간격",
              description:
                "문자 사이의 간격(자간)을 조절합니다. 본문은 보통 또는 약간 넓게, 대문자 위주의 짧은 타이틀은 살짝 넓게 설정하면 가독성과 디자인이 좋아집니다.",
            },
            {
              label: "줄 간격",
              description:
                "행과 행 사이의 간격(행간)을 정합니다. 본문은 1.5~1.7 정도가 읽기 좋고, 아주 짧은 제목은 1.25 정도로 줄이면 한 덩어리로 단단해 보입니다.",
            },
            {
              label: "굵기",
              description:
                "폰트 두께를 100~900 범위에서 조절합니다. 본문은 보통(400), 섹션 제목은 세미볼드(600), 강한 CTA 문구는 볼드(700) 정도를 추천합니다.",
            },
            {
              label: "텍스트 색상",
              description:
                "글자 색을 팔레트 또는 HEX 코드로 지정합니다. 본문은 대비가 높은 짙은 색을, 강조 문구는 브랜드 메인 색을 사용하는 것이 좋습니다.",
            },
            {
              label: "블록 배경색",
              description:
                "텍스트가 들어 있는 카드/박스 전체 배경색을 지정합니다. 공지사항, 강조 박스, 경고 문구 등을 만들 때 연한 배경색과 함께 사용하면 좋습니다.",
            },
            {
              label: "최대 너비",
              description:
                "한 줄 텍스트가 지나치게 길어지지 않도록 최대 줄 길이를 제한합니다. `본문 폭(60ch)`는 일반 문단에, `좁게(40ch)`는 카드/배너 같은 짧은 문구에 적합합니다.",
            },
          ],
        };
      case "button":
        return {
          title: "버튼 블록 튜토리얼",
          description:
            "폼 제출이나 링크 이동을 위한 CTA 버튼을 만들 때 사용하는 블록입니다. 라벨, 링크(URL), 정렬, 색상/크기를 조절해 원하는 액션 버튼을 구성해 보세요.",
          properties: [
            {
              label: "버튼 텍스트",
              description:
                "버튼 위에 표시될 문구입니다. 예: '지금 시작하기', '문의 남기기'. 짧고 행동을 유도하는 문장을 사용하는 것이 좋습니다.",
            },
            {
              label: "가로 패딩 (px)",
              description:
                "버튼 양 옆의 여백을 조절합니다. 값이 클수록 버튼이 가로로 넓어져 더 강조됩니다.",
            },
            {
              label: "세로 패딩 (px)",
              description:
                "버튼 위·아래 여백을 조절합니다. 값이 클수록 버튼 높이가 높아져 더 눈에 띱니다.",
            },
            {
              label: "버튼 링크",
              description:
                "버튼 클릭 시 이동할 URL 또는 앵커(#section)입니다. 외부 페이지, 페이지 내 섹션, 폼 제출 엔드포인트 등으로 연결할 수 있습니다.",
            },
            {
              label: "정렬",
              description:
                "해당 버튼이 포함된 영역 안에서 왼쪽/가운데/오른쪽 중 어디에 위치할지 결정합니다. 주요 CTA 버튼은 가운데 정렬이 많이 쓰입니다.",
            },
            {
              label: "텍스트 색상",
              description:
                "버튼 라벨 글자 색입니다. 채움 색상과 충분한 대비가 나도록 설정해야 가독성이 좋습니다.",
            },
            {
              label: "스타일",
              description:
                "버튼 외형 스타일입니다. '채움'은 꽉 찬 스타일, '외곽선'은 테두리만 있는 스타일, '고스트'는 배경 없이 텍스트/테두리만 있는 스타일입니다.",
            },
            {
              label: "채움 색상",
              description:
                "채움 스타일에서 버튼 내부를 채우는 색입니다. 브랜드 메인 색이나 강조 색을 사용하면 좋습니다.",
            },
            {
              label: "외곽선 색상",
              description:
                "외곽선/고스트 스타일에서 버튼 테두리 색입니다. 배경색과의 대비를 고려해 설정합니다.",
            },
            {
              label: "모서리 둥글기",
              description:
                "버튼 모서리를 얼마나 둥글게 처리할지 결정합니다. '없음'은 각진 버튼, '완전 둥글게'는 알약 모양 버튼입니다.",
            },
            {
              label: "버튼 너비 모드 / 버튼 고정 너비",
              description:
                "버튼이 컨테이너 너비에 맞춰 늘어날지(전체 폭), 내용 길이에 맞출지(자동), 고정 px 너비를 가질지 결정합니다.",
            },
            {
              label: "버튼 크기",
              description:
                "버튼 라벨 텍스트의 폰트 크기입니다. 중요한 CTA 버튼은 주변 텍스트보다 조금 더 크게 설정하면 좋습니다.",
            },
            {
              label: "줄 간격 / 글자 간격",
              description:
                "버튼 라벨의 행간과 자간을 조절합니다. 글자가 너무 답답해 보이면 자간을 약간 넓히고, 여러 줄 버튼 문구는 줄 간격을 조금 넓혀 주세요.",
            },
          ],
        };
      case "image":
        return {
          title: "이미지 블록 튜토리얼",
          description:
            "배너, 썸네일, 설명 이미지를 배치할 때 사용하는 블록입니다. 외부 이미지 URL을 입력하거나 업로드 이미지를 선택하고, 너비/정렬/모서리 둥글기를 조절해 레이아웃에 맞게 배치해 보세요.",
          properties: [
            {
              label: "이미지 소스",
              description:
                "이미지를 외부 URL에서 가져올지(URL), 빌더에 업로드한 에셋을 사용할지(파일 업로드) 선택합니다.",
            },
            {
              label: "이미지 URL / 이미지 파일 업로드",
              description:
                "URL 모드에서는 외부 이미지 주소를 입력하고, 업로드 모드에서는 로컬 이미지를 업로드해 `/api/image/:id` 형식으로 관리합니다.",
            },
            {
              label: "대체 텍스트",
              description:
                "이미지가 로드되지 않거나 스크린리더를 사용하는 사용자에게 보여질 설명 텍스트입니다. 이미지가 전달하는 의미를 한두 문장으로 작성해 주세요.",
            },
            {
              label: "카드 배경색",
              description:
                "이미지를 감싸는 카드 영역의 배경색입니다. 투명한 PNG 아이콘이나 로고를 올릴 때 배경을 살짝 깔아주면 더 잘 보입니다.",
            },
            {
              label: "정렬",
              description:
                "이미지가 포함된 영역 안에서 왼쪽/가운데/오른쪽 중 어디에 위치할지 결정합니다.",
            },
            {
              label: "너비 모드 / 고정 너비 (px)",
              description:
                "이미지를 내용 크기에 맞출지(auto) 또는 px 단위로 고정된 너비를 사용할지 선택합니다. 썸네일 그리드에서는 고정 너비를 사용하는 편이 레이아웃이 안정적입니다.",
            },
            {
              label: "모서리 둥글기",
              description:
                "이미지 카드 모서리 둥글기를 px 단위로 조절합니다. 아바타/아이콘은 완전 둥글게, 일반 사진은 살짝 둥글게 설정하면 자연스럽습니다.",
            },
          ],
        };
      case "list":
        return {
          title: "리스트 블록 튜토리얼",
          description:
            "불릿/번호 리스트를 만들 때 사용하는 블록입니다. 아이템 텍스트를 수정하고, 정렬/불릿 스타일을 바꿔 체크리스트나 단계별 안내 등을 표현할 수 있습니다.",
          properties: [
            {
              label: "리스트 아이템 (줄바꿈으로 구분)",
              description:
                "각 줄이 하나의 리스트 항목이 됩니다. 들여쓰기를 이용한 중첩 리스트는 TDD 기준의 변환 로직에 따라 자동으로 트리 구조로 변환됩니다.",
            },
            {
              label: "정렬",
              description:
                "리스트 전체를 왼쪽/가운데/오른쪽 중 어디에 정렬할지 결정합니다. 체크리스트는 왼쪽 정렬, 특징 요약은 가운데 정렬이 자주 사용됩니다.",
            },
            {
              label: "글자 크기 (px)",
              description:
                "리스트 텍스트의 폰트 크기를 조절합니다. 본문보다 약간 작게 설정하면 보조 정보 느낌을 줄 수 있습니다.",
            },
            {
              label: "줄 간격",
              description:
                "리스트 항목 내부의 행간을 조절합니다. 항목 내용이 길어질수록 1.5~1.8 정도의 넉넉한 값을 추천합니다.",
            },
            {
              label: "텍스트 색상",
              description:
                "리스트 텍스트의 색상입니다. 배경색과의 대비를 고려해 본문과 동일하거나 약간 연한 색상을 사용할 수 있습니다.",
            },
            {
              label: "블록 배경색",
              description:
                "리스트 전체 카드의 배경색입니다. 단계별 안내나 체크리스트 박스를 강조하는 용도로 사용할 수 있습니다.",
            },
            {
              label: "불릿 스타일",
              description:
                "불릿(●/○/■) 또는 번호(1., a., i.) 형식을 선택합니다. 숫자/알파벳/로마 숫자 스타일을 선택하면 자동으로 순서형 리스트(ordered)가 됩니다.",
            },
            {
              label: "아이템 간 여백 (px)",
              description:
                "각 리스트 항목 사이의 세로 간격입니다. 설명이 긴 항목이 많다면 여백을 넉넉히 두어 가독성을 확보하세요.",
            },
          ],
        };
      case "divider":
        return {
          title: "구분선 블록 튜토리얼",
          description:
            "섹션과 섹션 사이를 나누거나 콘텐츠를 시각적으로 구분할 때 사용하는 블록입니다. 정렬, 두께, 길이, 색상, 여백을 조절해 페이지 흐름을 정리해 보세요.",
          properties: [
            {
              label: "정렬",
              description:
                "구분선을 컨테이너 안에서 왼쪽/가운데/오른쪽 중 어디에 위치시킬지 결정합니다.",
            },
            {
              label: "두께",
              description:
                "선의 두께입니다. '얇게'는 가벼운 보조 구분선, '보통'은 섹션 경계를 확실히 나눌 때 사용합니다.",
            },
            {
              label: "길이 모드 / 고정 길이 (px)",
              description:
                "구분선을 전체 폭으로 쓸지, 내용에 맞출지, 또는 px 단위의 고정 길이를 사용할지 선택합니다.",
            },
            {
              label: "선 색상",
              description:
                "구분선 컬러입니다. 너무 진한 색보다는 섹션 배경보다 살짝 진한 정도의 중간 톤을 추천합니다.",
            },
            {
              label: "위/아래 여백",
              description:
                "구분선 위·아래에 들어가는 공백입니다. 값이 클수록 섹션이 더 명확하게 나뉘어 보입니다.",
            },
          ],
        };
      case "section":
        return {
          title: "섹션 블록 튜토리얼",
          description:
            "레이아웃의 큰 덩어리를 나누는 컨테이너 블록입니다. 배경색/배경 이미지/비디오, 위아래 패딩, 너비를 설정해 Hero, Features, Footer 같은 영역을 구성할 수 있습니다.",
          properties: [
            {
              label: "배경 색상",
              description:
                "섹션 전체의 기본 배경색입니다. 페이지의 큰 분위기를 결정하는 요소이므로, 섹션 간 배경 대비를 적절히 주는 것이 좋습니다.",
            },
            {
              label: "배경 이미지 소스 / URL / 파일 업로드",
              description:
                "섹션 배경으로 사용할 이미지를 외부 URL 또는 업로드 파일로 지정합니다. Hero 배경, 패턴, 질감 이미지를 설정할 때 사용합니다.",
            },
            {
              label: "배경 이미지 크기 / 위치 / 반복",
              description:
                "cover/contain/auto로 크기를 조절하고, 프리셋 또는 X/Y 퍼센트로 위치를 조절하며, 반복 여부를 설정해 패턴 형태로 사용할 수 있습니다.",
            },
            {
              label: "배경 비디오 소스 / URL / 파일 업로드",
              description:
                "섹션 배경에 비디오를 설정합니다. 시선을 끌어야 하는 Hero 영역 등에 사용하되, 가독성 저하를 막기 위해 텍스트 대비를 꼭 확인하세요.",
            },
            {
              label: "세로 패딩",
              description:
                "섹션 위·아래 여백입니다. 값이 클수록 섹션이 여유 있고 강조되어 보입니다. Hero 섹션은 넉넉한 패딩을, 보조 섹션은 중간 정도를 추천합니다.",
            },
          ],
        };
      case "video":
        return {
          title: "비디오 블록 튜토리얼",
          description:
            "YouTube/영상 URL 또는 직접 호스팅한 비디오를 삽입할 때 사용하는 블록입니다. 동영상 주소를 입력하고, 비율/정렬/재생 옵션을 조정해 페이지에 맞게 배치해 보세요.",
          properties: [
            {
              label: "비디오 소스 / 비디오 URL / 비디오 파일 업로드",
              description:
                "외부 동영상 URL(YouTube, Vimeo 등)을 직접 입력하거나, 비디오 파일을 업로드해 `/api/video/:id` 형태로 사용할 수 있습니다.",
            },
            {
              label: "포스터 이미지 URL",
              description:
                "동영상 재생 전/로딩 중에 보여줄 썸네일 이미지입니다. 영상의 핵심 장면이나 대표 이미지를 사용하면 클릭률을 높일 수 있습니다.",
            },
            {
              label: "카드 배경색",
              description:
                "비디오가 들어가는 카드 영역의 배경색입니다. 주변 섹션과의 대비를 위해 살짝 어둡거나 밝은 색을 설정할 수 있습니다.",
            },
            {
              label: "비디오 정렬",
              description:
                "비디오를 컨테이너 안에서 왼쪽/가운데/오른쪽 중 어디에 위치시킬지 결정합니다.",
            },
            {
              label: "비디오 너비 모드 / 고정 너비 (px)",
              description:
                "비디오를 내용 너비에 맞출지, 가로 전체를 채울지, 특정 px 너비로 고정할지 선택합니다.",
            },
            {
              label: "카드 패딩 / 카드 모서리 둥글기",
              description:
                "비디오 주변 카드의 안쪽 여백과 모서리 둥글기입니다. 카드형 레이아웃에서는 적당한 패딩과 둥근 모서리를 주면 디자인이 정돈됩니다.",
            },
            {
              label: "시작 시점 (초) / 종료 시점 (초)",
              description:
                "영상의 특정 구간만 재생하고 싶을 때 사용하는 옵션입니다. 예를 들어 10초~30초만 재생하도록 설정할 수 있습니다.",
            },
            {
              label: "화면 비율",
              description:
                "동영상 프레임 비율입니다. 대부분의 웹 영상은 16:9를 사용하며, 정사각형/세로형 콘텐츠는 1:1, 4:3 등을 사용할 수 있습니다.",
            },
            {
              label: "자동 재생 / 반복 재생 / 음소거 / 재생 컨트롤 표시",
              description:
                "자동 재생/반복 재생/음소거/컨트롤 표시 여부를 설정합니다. 자동 재생 영상은 보통 음소거를 함께 켜 두는 것이 좋습니다.",
            },
          ],
        };
      case "form":
        return {
          title: "폼 컨트롤러 블록 튜토리얼",
          description:
            "입력 필드(formInput/select/checkbox/radio)를 하나의 폼으로 묶는 컨트롤러입니다. 전송 대상, 전송 포맷, 너비, 여백 등을 설정해 네이티브 폼 제출을 구성하고, 필드 ID를 연결해 폼 구조를 완성할 수 있습니다.",
          properties: [
            {
              label: "전송 대상 / Webhook 설정",
              description:
                "폼 데이터를 내부 처리로만 사용할지, 외부 Webhook/Google Sheets 등으로 전송할지 결정하고, 목적지 URL/전송 포맷/HTTP 메서드 등을 설정합니다.",
            },
            {
              label: "추가 파라미터",
              description:
                "`key=value` 형식으로 줄바꿈해 작성하면, 모든 폼 제출에 공통으로 포함될 추가 파라미터를 지정할 수 있습니다. 예: `source=landing`.",
            },
            {
              label: "폼 너비 모드 / 폼 고정 너비 (px)",
              description:
                "폼 전체의 가로 폭을 자동/전체 폭/고정 px 값 중에서 선택합니다. 문의 폼은 보통 480~640px 정도의 고정 폭이 읽기 좋습니다.",
            },
            {
              label: "폼 위/아래 여백 (px)",
              description:
                "폼 블록 위·아래에 들어가는 공백입니다. 페이지 내 다른 섹션과의 간격을 조절할 때 사용합니다.",
            },
            {
              label: "성공 메시지 / 에러 메시지",
              description:
                "폼 전송 성공 또는 실패 시 사용자에게 보여줄 텍스트입니다. 명확하고 친절한 문구로 작성하는 것이 좋습니다.",
            },
            {
              label: "폼 필드 매핑",
              description:
                "폼 컨트롤러와 연결할 입력 필드(formInput/select/checkbox/radio)를 체크박스로 선택합니다. 체크된 필드만 실제 폼 제출 payload에 포함됩니다.",
            },
            {
              label: "Submit 버튼",
              description:
                "폼 제출을 담당할 버튼 블록을 지정합니다. 별도 버튼 블록을 만들어 이 컨트롤러와 연결하면, 해당 버튼 클릭 시 폼이 제출됩니다.",
            },
          ],
        };
      case "formInput":
        return {
          title: "폼 입력 블록 튜토리얼",
          description:
            "이름, 이메일 등 한 줄 텍스트 또는 긴 텍스트 입력 필드를 만들 때 사용하는 블록입니다. 레이블, 플레이스홀더, 필수 여부, 너비 등을 설정해 폼 컨트롤러와 함께 사용합니다.",
          properties: [
            {
              label: "라벨 타입 / 필드 라벨",
              description:
                "입력 필드 위나 옆에 표시될 설명입니다. 텍스트 또는 이미지로 라벨을 구성할 수 있으며, 사용자가 어떤 값을 입력해야 하는지 명확하게 알려줍니다.",
            },
            {
              label: "라벨 이미지 URL / 대체 텍스트",
              description:
                "라벨을 이미지로 사용할 때 경로와 alt 텍스트를 지정합니다. 로고형 라벨이나 아이콘 기반 UI를 만들 때 활용할 수 있습니다.",
            },
            {
              label: "전송 키",
              description:
                "이 입력값이 서버/웹훅에 전달될 때 사용되는 필드 이름입니다. 백엔드나 스프레드시트 컬럼명과 일치시키면 이후 처리가 편해집니다.",
            },
            {
              label: "필드 타입",
              description:
                "텍스트/이메일/긴 텍스트 중 어떤 형태의 입력을 받을지 결정합니다. 이메일 타입은 브라우저 기본 이메일 검증을 활용할 수 있습니다.",
            },
            {
              label: "Placeholder",
              description:
                "입력 전 필드 안에 흐릿하게 보여줄 안내 문구입니다. 예: '이메일을 입력해 주세요'.",
             },
             {
               label: "필수 필드",
               description:
                "체크 시 이 필드는 반드시 채워야 합니다. 이름/이메일 같은 필수 값에는 활성화하고, 선택 항목에는 비활성화하는 것을 추천합니다.",
             },
             {
               label: "텍스트 크기 / 줄간격 / 자간",
               description:
                "입력 값의 폰트 크기(px), 줄간격(px), 자간(px)을 조절해 폼 필드의 가독성과 분위기를 세밀하게 튜닝합니다.",
             },
             {
               label: "텍스트 정렬",
               description:
                "필드 안 텍스트를 왼쪽/가운데/오른쪽 중 어디에 정렬할지 결정합니다. 일반 입력은 왼쪽 정렬을 권장합니다.",
             },
             {
               label: "레이아웃 / 라벨/필드 간격",
               description:
                "라벨과 필드를 세로(stack) 또는 가로(inline)로 배치하고, inline 모드에서 라벨과 입력 사이 간격(px)을 조절합니다.",
             },
             {
               label: "너비 / 필드 고정 너비",
               description:
                "필드를 자동/전체 폭/고정 px 중 어떤 너비로 렌더링할지 결정합니다. 짧은 필드는 고정 값, 긴 입력은 전체 폭을 사용할 수 있습니다.",
             },
             {
               label: "필드 가로/세로 패딩",
               description:
                "입력 상자 안쪽 여백을 조절합니다. 값이 클수록 필드가 커지고 누르기/입력하기 편해집니다.",
             },
             {
               label: "필드 텍스트/채움/테두리 색상",
               description:
                "입력 텍스트, 배경, 테두리 색상을 각각 조절합니다. 에러 상태/강조 상태 등을 표현할 때 조합해서 사용할 수 있습니다.",
             },
             {
               label: "필드 모서리 둥글기",
               description:
                "입력 상자의 모서리를 얼마나 둥글게 할지 결정합니다. 페이지의 전체 디자인 톤과 맞춰 사용하세요.",
             },
          ],
        };
      case "formSelect":
        return {
          title: "폼 셀렉트 블록 튜토리얼",
          description:
            "드롭다운 선택 필드를 만들 때 사용하는 블록입니다. 옵션 목록과 기본 선택값, 너비를 설정해 폼 컨트롤러와 함께 사용합니다.",
          properties: [
            {
              label: "라벨 타입 / 필드 라벨",
              description:
                "셀렉트 필드의 제목 역할을 하는 라벨입니다. 텍스트 또는 이미지로 구성할 수 있으며, 선택해야 할 값의 의미를 설명합니다.",
            },
            {
              label: "전송 키",
              description:
                "선택된 옵션 값이 서버/웹훅에 전달될 때 사용되는 필드 이름입니다. 백엔드나 스프레드시트 컬럼명과 일치시키면 이후 처리가 편해집니다.",
            },
            {
              label: "옵션",
              description:
                "사용자가 선택할 수 있는 옵션 목록입니다. 라벨과 value를 함께 설정하며, '옵션 추가' 버튼으로 새 옵션을 만들 수 있습니다.",
            },
            {
              label: "필수 필드",
              description:
                "체크 시 반드시 하나의 옵션을 선택해야 합니다. 중요 선택 항목에는 필수로 설정하는 것을 권장합니다.",
            },
            {
              label: "셀렉트 텍스트 크기 / 줄간격 / 자간",
              description:
                "드롭다운 필드의 텍스트 타이포그래피를 px 단위로 조절해 가독성과 분위기를 맞춥니다.",
            },
            {
              label: "필드 너비 / 필드 고정 너비",
              description:
                "셀렉트 필드를 자동/전체 폭/고정 px 중 어떤 너비로 렌더링할지 결정합니다.",
            },
            {
              label: "셀렉트 가로/세로 패딩",
              description:
                "드롭다운 안쪽 여백을 조절해 클릭 영역과 시각적 무게감을 조정합니다.",
            },
            {
              label: "필드 텍스트/채움/테두리 색상",
              description:
                "선택 영역의 텍스트, 배경, 테두리 색상을 설정합니다. 폼 전체 톤과 잘 어울리는 색상을 사용하는 것이 좋습니다.",
            },
            {
              label: "필드 모서리 둥글기",
              description:
                "셀렉트 박스의 모서리를 얼마나 둥글게 표시할지 결정합니다.",
            },
          ],
        };
      case "formCheckbox":
        return {
          title: "폼 체크박스 블록 튜토리얼",
          description:
            "여러 항목 중 복수 선택이 필요한 경우 사용하는 체크박스 그룹 블록입니다. 그룹 타이틀과 옵션 라벨/이미지를 설정해 동의 항목이나 관심사 선택 등을 구성할 수 있습니다.",
          properties: [
            {
              label: "그룹 타이틀 타입 / 그룹 타이틀",
              description:
                "체크박스 그룹 전체의 제목입니다. 텍스트 또는 이미지로 표현할 수 있으며, 사용자가 어떤 범주를 선택하는지 알려줍니다.",
            },
            {
              label: "그룹 타이틀 이미지 소스 / URL / 파일 업로드",
              description:
                "그룹 라벨을 이미지로 사용할 때, URL 또는 업로드된 이미지를 선택합니다.",
            },
            {
              label: "전송 키",
              description:
                "체크된 옵션들의 값이 서버/웹훅에 전달될 때 사용되는 필드 이름입니다.",
            },
            {
              label: "옵션 / 옵션 이미지 소스",
              description:
                "각 체크박스 옵션의 라벨/값/이미지를 설정합니다. URL 또는 업로드 이미지로 옵션별 아이콘을 붙일 수 있습니다.",
            },
            {
              label: "필수 필드",
              description:
                "체크 시 하나 이상 옵션을 선택해야 합니다. 약관 동의 등 필수 동의 항목에 사용합니다.",
            },
            {
              label: "체크박스 텍스트 크기 / 줄간격 / 자간",
              description:
                "체크박스 라벨의 폰트 크기, 줄간격, 자간을 조절합니다. 항목이 길어질수록 줄간격을 넉넉히 두는 것이 좋습니다.",
            },
          ],
        };
      case "formRadio":
        return {
          title: "폼 라디오 블록 튜토리얼",
          description:
            "여러 옵션 중 하나만 선택해야 할 때 사용하는 라디오 버튼 그룹 블록입니다. 옵션 라벨/이미지와 기본 선택값을 설정해 요금제 선택 등 단일 선택 시나리오를 구성할 수 있습니다.",
          properties: [
            {
              label: "그룹 타이틀 타입 / 그룹 타이틀",
              description:
                "라디오 그룹의 제목입니다. 요금제 이름, 질문 문구 등 단일 선택의 맥락을 설명합니다.",
            },
            {
              label: "그룹 타이틀 이미지 소스 / URL / 파일 업로드",
              description:
                "그룹 라벨을 이미지로 사용할 때, URL 또는 업로드 이미지를 선택합니다.",
            },
            {
              label: "전송 키",
              description:
                "선택된 하나의 옵션 값이 서버/웹훅에 전달될 때 사용되는 필드 이름입니다.",
            },
            {
              label: "옵션 / 옵션 이미지 소스",
              description:
                "각 라디오 옵션의 라벨/값/이미지를 설정합니다. 옵션별 아이콘이나 썸네일을 붙여 더 풍부한 선택 UI를 만들 수 있습니다.",
            },
            {
              label: "필수 필드",
              description:
                "체크 시 반드시 하나의 옵션을 선택해야 합니다. 요금제/유형 선택처럼 반드시 선택이 필요한 경우에 사용합니다.",
            },
            {
              label: "라디오 텍스트 크기 / 줄간격 / 자간",
              description:
                "라디오 라벨의 폰트 크기, 줄간격, 자간을 조절합니다. 옵션 설명이 긴 경우 줄간격을 넉넉히 두세요.",
            },
          ],
        };
      default:
        return {
          title: "블록 튜토리얼",
          description: "이 블록에 대한 자세한 도움말은 추후 추가될 예정입니다.",
        };
    }
  };

  return (
    <aside
      data-testid="properties-sidebar"
      className="w-80 p-4 text-sm border-l border-slate-800 flex flex-col gap-4 overflow-auto pb-scroll bg-slate-950/40"
      onKeyDownCapture={(e) => {
        // 속성 패널 안에서 발생한 키 입력은 에디터 단축키/텍스트 블록 편집으로 전달되지 않도록 막는다.
        e.stopPropagation();
      }}
    >
      <h2 className="font-medium mb-2 flex items-center gap-2 text-slate-200">
        <SlidersHorizontal className="w-4 h-4 text-sky-400" aria-hidden="true" />
        <span>속성 패널</span>
      </h2>
      {selectedBlockId ? (
        <div className="space-y-3">
          <div className="flex gap-2 text-[11px]">
            <button
              type="button"
              className="flex-1 rounded border border-slate-700 bg-slate-900 px-2 py-1 text-slate-100 hover:bg-red-900/60 hover:border-red-700"
              onClick={() => removeBlock(selectedBlockId)}
            >
              <span className="inline-flex items-center gap-2">
                <Trash2 className="w-3 h-3" aria-hidden="true" />
                <span>블록 삭제</span>
              </span>
            </button>
            <button
              type="button"
              className="flex-1 rounded border border-slate-700 bg-slate-900 px-2 py-1 text-slate-100 hover:bg-slate-800"
              onClick={() => duplicateBlock(selectedBlockId)}
            >
              <span className="inline-flex items-center gap-2">
                <Copy className="w-3 h-3" aria-hidden="true" />
                <span>블록 복제</span>
              </span>
            </button>
          </div>
          <div className="flex justify-end text-[11px]">
            <button
              type="button"
              className="inline-flex items-center gap-1 rounded border border-slate-700 bg-slate-900 px-2 py-1 text-slate-100 hover:bg-slate-800"
              onClick={() => setHelpOpen(true)}
            >
              <HelpCircle className="w-3 h-3" aria-hidden="true" />
              <span>HELP</span>
            </button>
          </div>
          {(() => {
            const selectedBlock = blocks.find((b) => b.id === selectedBlockId);
            if (!selectedBlock) return null;

            if (selectedBlock.type === "text") {
              const textProps = selectedBlock.props as TextBlockProps;

              return (
                <TextPropertiesPanel
                  textProps={textProps}
                  selectedBlockId={selectedBlockId}
                  updateBlock={(id, partial) => updateBlock(id, partial as any)}
                  editingBlockId={editingBlockId}
                  setEditingText={setEditingText}
                />
              );
            }

            if (selectedBlock.type === "button") {
              const buttonProps = selectedBlock.props as ButtonBlockProps;

              return (
                <ButtonPropertiesPanel
                  buttonProps={buttonProps}
                  selectedBlockId={selectedBlockId}
                  updateBlock={(id, partial) => updateBlock(id, partial as any)}
                />
              );
            }

            if (selectedBlock.type === "list") {
              const listProps = selectedBlock.props as ListBlockProps;

              return (
                <ListPropertiesPanel
                  listProps={listProps}
                  selectedBlockId={selectedBlockId}
                  selectedListItemId={selectedListItemId}
                  updateBlock={(id, partial) => updateBlock(id, partial as any)}
                />
              );
            }

            if (selectedBlock.type === "divider") {
              const dividerProps = selectedBlock.props as any;

              return (
                <DividerPropertiesPanel
                  dividerProps={dividerProps}
                  selectedBlockId={selectedBlockId}
                  updateBlock={(id, partial) => updateBlock(id, partial as any)}
                />
              );
            }

            if (selectedBlock.type === "image") {
              const imageProps = selectedBlock.props as any;

              return (
                <ImagePropertiesPanel
                  imageProps={imageProps}
                  selectedBlockId={selectedBlockId}
                  updateBlock={(id, partial) => updateBlock(id, partial as any)}
                />
              );
            }

            if (selectedBlock.type === "video") {
              const videoProps = selectedBlock.props as VideoBlockProps;

              return (
                <VideoPropertiesPanel
                  videoProps={videoProps}
                  selectedBlockId={selectedBlockId}
                  updateBlock={(id, partial) => updateBlock(id, partial as any)}
                />
              );
            }

            if (selectedBlock.type === "section") {
              const sectionProps = selectedBlock.props as SectionBlockProps;

              return (
                <SectionPropertiesPanel
                  sectionProps={sectionProps}
                  selectedBlockId={selectedBlockId}
                  updateBlock={(id, partial) => updateBlock(id, partial as any)}
                />
              );
            }

            if (selectedBlock.type === "formInput") {
              return (
                <FormInputPropertiesPanel
                  block={selectedBlock}
                  selectedBlockId={selectedBlockId}
                  updateBlock={(id, partial) => updateBlock(id, partial as any)}
                />
              );
            }

            if (selectedBlock.type === "formSelect") {
              return (
                <FormSelectPropertiesPanel
                  block={selectedBlock}
                  selectedBlockId={selectedBlockId}
                  updateBlock={(id, partial) => updateBlock(id, partial as any)}
                />
              );
            }

            if (selectedBlock.type === "formCheckbox") {
              return (
                <FormCheckboxPropertiesPanel
                  block={selectedBlock}
                  selectedBlockId={selectedBlockId}
                  updateBlock={(id, partial) => updateBlock(id, partial as any)}
                />
              );
            }

            if (selectedBlock.type === "formRadio") {
              return (
                <FormRadioPropertiesPanel
                  block={selectedBlock}
                  selectedBlockId={selectedBlockId}
                  updateBlock={(id, partial) => updateBlock(id, partial as any)}
                />
              );
            }

            if (selectedBlock.type === "form") {
              return (
                <FormControllerPanel
                  block={selectedBlock}
                  blocks={blocks}
                  selectedBlockId={selectedBlockId}
                  updateBlock={(id, partial) => updateBlock(id, partial as any)}
                />
              );
            }

            return null;
          })()}
        </div>
      ) : (
        <ProjectPropertiesPanel />
      )}
      {helpOpen && (() => {
        const help = getHelpContentForSelectedBlock();
        if (!help) return null;

        return (
          <div className="fixed inset-0 z-40 flex items-center justify-center bg-black/60">
            <div className="w-full max-w-md rounded-lg border border-slate-700 bg-slate-900 p-4 text-xs text-slate-100 shadow-xl">
              <div className="flex items-center justify-between mb-2">
                <h3 className="text-sm font-medium">{help.title}</h3>
                <button
                  type="button"
                  className="text-slate-400 hover:text-slate-100 text-xs"
                  onClick={() => setHelpOpen(false)}
                >
                  닫기
                </button>
              </div>
              <p className="text-[11px] text-slate-200 whitespace-pre-line">{help.description}</p>
              {help.properties && help.properties.length > 0 && (
                <div className="mt-3 border-t border-slate-700 pt-2 space-y-2">
                  <h4 className="text-[11px] font-semibold text-slate-200">속성별 설명</h4>
                  <ul className="space-y-1">
                    {help.properties.map((prop) => (
                      <li key={prop.label}>
                        <div className="text-[11px] font-semibold text-slate-100">{prop.label}</div>
                        <div className="text-[11px] text-slate-300">{prop.description}</div>
                      </li>
                    ))}
                  </ul>
                </div>
              )}
            </div>
          </div>
        );
      })()}
    </aside>
  );
}
