/* ────────────────────────────────────────────────────────────
   cutform.jsx — 컷 편집 폼 (선택된 슬라이드의 우측 인스펙터)
   Wave C. CONTRACT §2 슬라이드 JSON v3 필드를 한 글자도 안 바꾸고 매핑.
   필드: title · content[] · narration · layout_suggestion(14종)
         · notes(화면설명) · diagram_subtype(HUB 계열 5종) · steps_style(arrow|numbered)
         · card_count(CARD) · content_density(low|normal|high)
         · illustration_needed/illustration_prompt · confirmed
   도메인 추가 UI: 표현형식 배지(EXPR — 강사+아나운서/내용만/전자칠판/대담, 서버 비저장)
   자동 레이아웃 추천: recommendLayout(slide) (core.jsx 정본 인용)
   저장: 디바운스 후 onPatch(slideId, partial) → 상위에서 PATCH /api/projects/:id/slides/:slideId
         (낙관적). 즉시(블러/엔터) 저장도 onPatch로.
   design.zip 승계: slide-editor-ui.jsx 의 Sec/Row/Seg/Stepper 패턴, inspector.jsx 섹션 구조.
   해요체·이모지 없음·플랫·tokens 변수만.
   ──────────────────────────────────────────────────────────── */

/* HUB 계열 도식 5종(storyboard-domain) */
const DIAGRAM_SUBTYPES = [
  { key: "hub", label: "방사형" },
  { key: "flow", label: "흐름" },
  { key: "tree", label: "계층" },
  { key: "cycle", label: "순환" },
  { key: "cause", label: "원인-결과" },
];
const CONTENT_DENSITY = [
  { key: "low", label: "낮음" },
  { key: "normal", label: "보통" },
  { key: "high", label: "높음" },
];

/* ── 작은 폼 프리미티브 (slide-editor-ui.jsx 패턴 승계) ── */
function FSec({ label, hint, right }) {
  return React.createElement("div", { style: { display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 8, marginBottom: 8 } },
    React.createElement("span", { style: { fontSize: 11.5, fontWeight: 700, color: "var(--label-alt)", letterSpacing: "0.02em" } }, label),
    right || (hint ? React.createElement("span", { className: "t-caption-2", style: { color: "var(--label-assist)" } }, hint) : null));
}

/* 세그먼트 선택(작은 enum) — value 일치 시 활성 */
function FSeg({ value, options, onChange, wrap }) {
  return React.createElement("div", {
    style: { display: "flex", flexWrap: wrap ? "wrap" : "nowrap", padding: 2, gap: 2, borderRadius: "var(--r-sm)", background: "var(--bg-alt)" },
  },
    options.map(([v, l]) => React.createElement("button", {
      key: String(v), onClick: () => onChange(v),
      style: {
        minWidth: 30, height: 28, padding: "0 10px", borderRadius: 6, border: "none", cursor: "pointer",
        fontSize: 12, fontWeight: 700, transition: "all var(--t-fast)",
        background: value === v ? "var(--bg-normal)" : "transparent",
        color: value === v ? "var(--primary)" : "var(--label-alt)",
        boxShadow: value === v ? "var(--sh-1)" : "none",
      },
    }, l)));
}

/* 숫자 스텝퍼 */
function FStepper({ value, min, max, step, onChange, unit }) {
  const set = (v) => onChange(Math.max(min, Math.min(max, v)));
  const n = typeof value === "number" ? value : min;
  return React.createElement("div", {
    style: { display: "inline-flex", alignItems: "center", gap: 2, border: "1px solid var(--border)", borderRadius: "var(--r-sm)", height: 32, background: "var(--bg-normal)" },
  },
    React.createElement("button", { onClick: () => set(n - step), style: { width: 28, height: "100%", border: "none", background: "transparent", cursor: "pointer", color: "var(--label-alt)", fontSize: 16, fontWeight: 700 } }, "−"),
    React.createElement("span", { className: "tnum", style: { minWidth: 44, textAlign: "center", fontSize: 12.5, fontWeight: 700, color: "var(--label-normal)" } }, `${n}${unit || ""}`),
    React.createElement("button", { onClick: () => set(n + step), style: { width: 28, height: "100%", border: "none", background: "transparent", cursor: "pointer", color: "var(--label-alt)", fontSize: 16, fontWeight: 700 } }, "+"));
}

/* ── 표현형식 선택(EXPR — 서버 비저장 편집 메타 _expr) ── */
function ExprPicker({ value, onChange }) {
  const keys = ["lecturer", "content", "board", "talk"];
  return React.createElement("div", { style: { display: "flex", flexWrap: "wrap", gap: 6 } },
    keys.map((k) => {
      const e = EXPR[k];
      const active = value === k;
      return React.createElement("button", {
        key: k, onClick: () => onChange(k),
        style: {
          display: "inline-flex", alignItems: "center", gap: 5, height: 28, padding: "0 11px",
          borderRadius: "var(--r-full)", cursor: "pointer", fontSize: 12, fontWeight: 700,
          background: active ? e.bg : "var(--bg-normal)",
          color: active ? e.color : "var(--label-alt)",
          border: active ? `1px solid ${e.color}` : "1px solid var(--border)",
          transition: "all var(--t-fast)",
        },
      },
        React.createElement("span", { style: { width: 6, height: 6, borderRadius: "50%", background: active ? e.color : "var(--label-assist)" } }),
        e.label);
    }));
}

/* ── 레이아웃 14종 picker (추천 강조) ── */
function LayoutPicker({ value, recommended, onChange }) {
  return React.createElement("div", { style: { display: "flex", flexWrap: "wrap", gap: 6 } },
    LAYOUT_KEYS.map((k) => {
      const m = layoutMeta(k);
      const active = value === k;
      const isRec = recommended === k && !active;
      return React.createElement("button", {
        key: k, onClick: () => onChange(k),
        title: isRec ? "자동 추천" : undefined,
        style: {
          position: "relative", height: 30, padding: "0 11px", borderRadius: "var(--r-sm)", cursor: "pointer",
          fontSize: 12, fontWeight: 700, transition: "all var(--t-fast)",
          background: active ? "var(--primary-light)" : "var(--bg-normal)",
          color: active ? "var(--primary)" : "var(--label-neutral)",
          border: active ? "1px solid var(--primary)" : (isRec ? "1px dashed var(--primary-assist)" : "1px solid var(--border)"),
        },
      },
        m.label,
        isRec ? React.createElement("span", { style: { position: "absolute", top: -6, right: -4, height: 14, padding: "0 4px", borderRadius: "var(--r-full)", background: "var(--primary)", color: "#fff", fontSize: 9, fontWeight: 700, lineHeight: "14px" } }, "추천") : null);
    }));
}

/* ── 콘텐츠 키워드 칩 편집(content[]) ── */
function ContentChips({ items, onChange }) {
  const [draft, setDraft] = useState("");
  const list = Array.isArray(items) ? items : [];
  function add() {
    const v = draft.trim();
    if (!v) return;
    onChange([...list, v]);
    setDraft("");
  }
  function removeAt(i) { onChange(list.filter((_, j) => j !== i)); }
  function editAt(i, v) { onChange(list.map((x, j) => (j === i ? v : x))); }

  return React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 8 } },
    React.createElement("div", { style: { display: "flex", flexWrap: "wrap", gap: 6 } },
      list.length === 0
        ? React.createElement("span", { className: "t-caption-1", style: { color: "var(--label-assist)" } }, "핵심 키워드 2~4개를 더해요. 나레이션과 중복하지 않아요.")
        : list.map((c, i) => React.createElement("span", {
            key: i,
            style: { display: "inline-flex", alignItems: "center", gap: 4, height: 28, padding: "0 4px 0 10px", borderRadius: "var(--r-full)", background: "var(--bg-alt)", border: "1px solid var(--border)" },
          },
            React.createElement("input", {
              value: c,
              onChange: (e) => editAt(i, e.target.value),
              style: { border: "none", outline: "none", background: "transparent", fontSize: 12.5, fontWeight: 600, color: "var(--label-neutral)", fontFamily: "var(--font)", width: `${Math.max(2, (c || "").length)}ch`, minWidth: 24 },
            }),
            React.createElement("button", {
              onClick: () => removeAt(i), "aria-label": "삭제",
              style: { width: 18, height: 18, borderRadius: "50%", border: "none", background: "transparent", cursor: "pointer", color: "var(--label-alt)", display: "inline-flex", alignItems: "center", justifyContent: "center", fontSize: 13, fontWeight: 700 },
            }, "×")))),
    React.createElement("div", { style: { display: "flex", gap: 6 } },
      React.createElement("input", {
        value: draft,
        placeholder: "키워드 추가 후 Enter",
        onChange: (e) => setDraft(e.target.value),
        onKeyDown: (e) => { if (e.key === "Enter") { e.preventDefault(); add(); } },
        style: { flex: 1, height: 34, padding: "0 12px", borderRadius: "var(--r-sm)", border: "1px solid var(--border)", background: "var(--bg-normal)", fontSize: 13, color: "var(--label-normal)", fontFamily: "var(--font)", outline: "none" },
      }),
      React.createElement(Button, { kind: "outline", size: "sm", onClick: add, disabled: !draft.trim() }, "추가")));
}

/* ── 컷 편집 폼 본체 ──
   props: slide (정규화된 객체), onPatch(partial)=>void (디바운스/즉시 상위에서 처리),
          saving(bool), savedAt(number|null) */
function CutEditForm({ slide, onPatch, saving, savedAt, showPreview = true, hideNarration = false }) {
  if (!slide) {
    return React.createElement("div", { style: { padding: "40px 20px", textAlign: "center" } },
      React.createElement("p", { className: "t-body-2", style: { color: "var(--label-alt)", margin: 0 } }, "왼쪽에서 슬라이드를 선택하면 여기에서 편집할 수 있어요."));
  }
  const rec = recommendLayout(slide);
  const isHub = slide.layout_suggestion === "HUB";
  const isSteps = slide.layout_suggestion === "STEPS";
  const isCard = slide.layout_suggestion === "CARD";
  const titleOver = (slide.title || "").length > 15;

  const sectionGap = { display: "flex", flexDirection: "column", gap: 7 };

  return React.createElement("div", { style: { display: "flex", flexDirection: "column", height: "100%" } },
    /* 헤더: 페이지 번호 + 저장 상태 + 확정 토글 */
    React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 10, padding: "14px 16px", borderBottom: "1px solid var(--line-neutral)" } },
      React.createElement("span", { className: "tnum", style: { fontSize: 13, fontWeight: 700, color: "#fff", background: "var(--primary)", minWidth: 30, height: 24, borderRadius: "var(--r-xs)", display: "inline-flex", alignItems: "center", justifyContent: "center", padding: "0 7px" } }, String(slide.id).padStart(2, "0")),
      React.createElement("span", { className: "t-label-1", style: { color: "var(--label-normal)" } }, "컷 편집"),
      React.createElement(SaveIndicator, { saving, savedAt, style: { marginLeft: "auto" } })),

    React.createElement("div", { style: { flex: 1, overflowY: "auto", padding: "16px", display: "flex", flexDirection: "column", gap: 20 } },
      /* 레이아웃 적용 실시간 미리보기 — showPreview=false(PPT 3-패널: 중앙에 이미 큰 미리보기)면 숨김 */
      (showPreview && typeof SlidePreview === "function")
        ? React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 7 } },
            React.createElement(FSec, { label: "미리보기", right: React.createElement(LayoutBadge, { layout: slide.layout_suggestion, sm: true }) }),
            React.createElement("div", { style: { boxShadow: "var(--sh-1)", borderRadius: "var(--r-sm)" } }, React.createElement(SlidePreview, { slide })))
        : null,

      /* 화면 제목 */
      React.createElement("div", { style: sectionGap },
        React.createElement(FSec, { label: "화면 제목", hint: "15자 이내 권장", right: titleOver ? React.createElement("span", { className: "t-caption-2", style: { color: "var(--caution)", fontWeight: 700 } }, `${(slide.title || "").length}자 · 길어요`) : React.createElement("span", { className: "t-caption-2 tnum", style: { color: "var(--label-assist)" } }, `${(slide.title || "").length}/15`) }),
        React.createElement("input", {
          value: slide.title || "",
          placeholder: "화면 제목",
          onChange: (e) => onPatch({ title: e.target.value }),
          style: { width: "100%", height: 38, padding: "0 12px", borderRadius: "var(--r-sm)", border: `1px solid ${titleOver ? "var(--caution)" : "var(--border)"}`, background: "var(--bg-normal)", fontSize: 14, fontWeight: 600, color: "var(--label-normal)", fontFamily: "var(--font)", outline: "none" },
        })),

      /* 레이아웃 14종 + 자동 추천 */
      React.createElement("div", { style: sectionGap },
        React.createElement(FSec, { label: "레이아웃", right: (rec && rec !== slide.layout_suggestion)
          ? React.createElement("button", {
              onClick: () => onPatch({ layout_suggestion: rec }),
              style: { display: "inline-flex", alignItems: "center", gap: 5, height: 22, padding: "0 9px", borderRadius: "var(--r-full)", border: "1px dashed var(--primary-assist)", background: "var(--bg-normal)", color: "var(--primary)", fontSize: 11, fontWeight: 700, cursor: "pointer" },
            }, `추천: ${layoutMeta(rec).label} 적용`)
          : React.createElement("span", { className: "t-caption-2", style: { color: "var(--label-assist)" } }, "추천과 일치") }),
        React.createElement(LayoutPicker, { value: slide.layout_suggestion, recommended: rec, onChange: (k) => onPatch({ layout_suggestion: k }) })),

      /* 표현형식(EXPR — 편집 메타) */
      React.createElement("div", { style: sectionGap },
        React.createElement(FSec, { label: "표현형식", hint: "강의 연출" }),
        React.createElement(ExprPicker, { value: slide._expr || "content", onChange: (k) => onPatch({ _expr: k }) })),

      /* 화면구조화 — 레이아웃별 추가 옵션 */
      (isHub || isSteps || isCard) ? React.createElement("div", { style: sectionGap },
        React.createElement(FSec, { label: "화면구조화" }),
        React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 12 } },
          isHub ? React.createElement(FRowInline, { label: "도식 종류" },
            React.createElement(FSeg, { wrap: true, value: slide.diagram_subtype || "hub", options: DIAGRAM_SUBTYPES.map((d) => [d.key, d.label]), onChange: (v) => onPatch({ diagram_subtype: v }) })) : null,
          isSteps ? React.createElement(FRowInline, { label: "단계 표시" },
            React.createElement(FSeg, { value: slide.steps_style || "arrow", options: [["arrow", "화살표"], ["numbered", "번호"]], onChange: (v) => onPatch({ steps_style: v }) })) : null,
          isCard ? React.createElement(FRowInline, { label: "카드 개수" },
            React.createElement(FStepper, { value: typeof slide.card_count === "number" ? slide.card_count : 3, min: 1, max: 8, step: 1, onChange: (v) => onPatch({ card_count: v }) })) : null)) : null,

      /* 콘텐츠 키워드 */
      React.createElement("div", { style: sectionGap },
        React.createElement(FSec, { label: "핵심 키워드", hint: "화면 표시 문구" }),
        React.createElement(ContentChips, { items: slide.content, onChange: (arr) => onPatch({ content: arr }) })),

      /* 나레이션(원문 보존) — PPT 뷰에선 캔버스 아래 영역으로 옮겨 중복을 피하려고 hideNarration 으로 숨겨요. */
      hideNarration ? null : React.createElement("div", { style: sectionGap },
        React.createElement(FSec, { label: "나레이션", hint: "성우 낭독 원문" }),
        React.createElement("textarea", {
          value: slide.narration || "",
          placeholder: "성우가 낭독할 원고 원문이에요. 원문을 그대로 보존해요.",
          onChange: (e) => onPatch({ narration: e.target.value }),
          rows: 6,
          style: { width: "100%", minHeight: 120, resize: "vertical", padding: "10px 12px", borderRadius: "var(--r-sm)", border: "1px solid var(--border)", background: "var(--bg-normal)", fontSize: 13.5, lineHeight: 1.65, color: "var(--label-normal)", fontFamily: "var(--font)", outline: "none" },
        })),

      /* 화면설명(notes) */
      React.createElement("div", { style: sectionGap },
        React.createElement(FSec, { label: "화면설명", hint: "제작 메모" }),
        React.createElement("textarea", {
          value: slide.notes || "",
          placeholder: "화면 연출·제작 메모를 적어요. (PPTX 노트로 들어가요.)",
          onChange: (e) => onPatch({ notes: e.target.value }),
          rows: 3,
          style: { width: "100%", minHeight: 64, resize: "vertical", padding: "10px 12px", borderRadius: "var(--r-sm)", border: "1px solid var(--border)", background: "var(--bg-normal)", fontSize: 13, lineHeight: 1.6, color: "var(--label-neutral)", fontFamily: "var(--font)", outline: "none" },
        })),

      /* 콘텐츠 밀도 */
      React.createElement(FRowInline, { label: "콘텐츠 밀도" },
        React.createElement(FSeg, { value: slide.content_density || "normal", options: CONTENT_DENSITY.map((d) => [d.key, d.label]), onChange: (v) => onPatch({ content_density: v }) })),

      /* 삽화 */
      React.createElement("div", { style: sectionGap },
        React.createElement(FSec, { label: "삽화", right: React.createElement("label", { style: { display: "inline-flex", alignItems: "center", gap: 6, cursor: "pointer", fontSize: 12, fontWeight: 600, color: "var(--label-neutral)" } },
          React.createElement("input", { type: "checkbox", checked: !!slide.illustration_needed, onChange: (e) => onPatch({ illustration_needed: e.target.checked }) }), "삽화 필요") }),
        slide.illustration_needed ? React.createElement("textarea", {
          value: slide.illustration_prompt || "",
          placeholder: "이미지 생성 프롬프트를 적어요.",
          onChange: (e) => onPatch({ illustration_prompt: e.target.value }),
          rows: 2,
          style: { width: "100%", minHeight: 48, resize: "vertical", padding: "9px 12px", borderRadius: "var(--r-sm)", border: "1px solid var(--border)", background: "var(--bg-normal)", fontSize: 12.5, lineHeight: 1.55, color: "var(--label-neutral)", fontFamily: "var(--font)", outline: "none" },
        }) : null,
        slide.illustration_url ? React.createElement("img", { src: slide.illustration_url, alt: "삽화 미리보기", style: { width: "100%", borderRadius: "var(--r-sm)", border: "1px solid var(--border)", marginTop: 4 }, onError: (e) => { e.target.style.display = "none"; } }) : null),

      /* 확정 */
      React.createElement("div", { style: { marginTop: 4, paddingTop: 14, borderTop: "1px solid var(--line-neutral)" } },
        React.createElement("label", { style: { display: "flex", alignItems: "center", gap: 9, cursor: "pointer" } },
          React.createElement("input", { type: "checkbox", checked: !!slide.confirmed, onChange: (e) => onPatch({ confirmed: e.target.checked }) }),
          React.createElement("span", { className: "t-label-1", style: { color: slide.confirmed ? "var(--positive)" : "var(--label-neutral)" } }, slide.confirmed ? "확정됨" : "이 컷을 확정"))))
  );
}

function FRowInline({ label, children }) {
  return React.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10 } },
    React.createElement("span", { style: { fontSize: 12.5, fontWeight: 600, color: "var(--label-neutral)" } }, label),
    children);
}

/* 저장 상태 인디케이터 — 자동저장 진행/완료 */
function SaveIndicator({ saving, savedAt, style }) {
  if (saving) {
    return React.createElement("span", { style: { display: "inline-flex", alignItems: "center", gap: 6, ...(style || {}) } },
      React.createElement(Spinner, { s: 12 }),
      React.createElement("span", { className: "t-caption-1", style: { color: "var(--label-alt)" } }, "저장 중"));
  }
  if (savedAt) {
    return React.createElement("span", { style: { display: "inline-flex", alignItems: "center", gap: 5, ...(style || {}) } },
      React.createElement("svg", { width: 13, height: 13, viewBox: "0 0 24 24", fill: "none", stroke: "var(--positive)", strokeWidth: 2.6, strokeLinecap: "round", strokeLinejoin: "round" }, React.createElement("path", { d: "M20 6 9 17l-5-5" })),
      React.createElement("span", { className: "t-caption-1", style: { color: "var(--label-alt)" } }, "저장됨"));
  }
  return null;
}

Object.assign(window, {
  CutEditForm, ContentChips, LayoutPicker, ExprPicker, SaveIndicator,
  FSec, FSeg, FStepper, FRowInline, DIAGRAM_SUBTYPES, CONTENT_DENSITY,
});
