/* ────────────────────────────────────────────────────────────
   settings.jsx — 관리자용 AI 설정 패널 (AI 원고 파싱: 멀티 프로바이더)
   관리자 페이지(admin.jsx)의 "API관리" 탭에서 패널로 렌더한다.
   계약(검증됨):
     GET /api/settings/ai  (관리자) ->
       { provider:"openai"|"gemini", model:string,
         models:{ openai:string[], gemini:string[] },
         openai:{ configured:boolean, maskedKey:string|null },
         gemini:{ configured:boolean, maskedKey:string|null } }
     PUT /api/settings/ai  {provider?, model?, openaiKey?, geminiKey?} (부분 업데이트)
        -> { ok:true, ...위 GET shape }
        · 키에 "" 를 보내면 해당 키 삭제(비활성).
     비관리자 403. 키 원본은 서버가 절대 주지 않음(마스킹만).
   Button/Pill/Spinner(core.jsx) 재사용.
   해요체·이모지 없음·플랫·tokens 변수만. 키 원본은 저장 후 입력을 비워요.
   ──────────────────────────────────────────────────────────── */

/* 프로바이더 메타(라벨/플레이스홀더/발급처) — ChatGPT(OpenAI) + Gemini(Google) */
const AI_PROVIDERS = [
  { key: "openai", label: "ChatGPT (OpenAI)", placeholder: "sk-...", keyField: "openaiKey", issuer: "platform.openai.com" },
  { key: "gemini", label: "Gemini (Google)", placeholder: "AIza... (Google AI Studio 키)", keyField: "geminiKey", issuer: "aistudio.google.com/apikey" },
];
const DIRECT_MODEL = "__direct__";
function providerMeta(k) { return AI_PROVIDERS.find((p) => p.key === k) || AI_PROVIDERS[0]; }

/* GET 응답 정규화(데이터 결함 방어) */
function normAiSettings(data) {
  data = data || {};
  const provider = (data.provider === "gemini") ? "gemini" : "openai";
  const models = data.models || {};
  return {
    provider,
    model: data.model || "",
    models: {
      openai: Array.isArray(models.openai) ? models.openai : [],
      gemini: Array.isArray(models.gemini) ? models.gemini : [],
    },
    openai: {
      configured: !!(data.openai && data.openai.configured),
      maskedKey: (data.openai && data.openai.maskedKey) || null,
    },
    gemini: {
      configured: !!(data.gemini && data.gemini.configured),
      maskedKey: (data.gemini && data.gemini.maskedKey) || null,
    },
  };
}

/* ── 프로바이더 세그먼트 토글 ── */
function ProviderSegment({ value, onChange, disabled }) {
  return React.createElement("div", {
    role: "tablist",
    style: { display: "flex", gap: 4, padding: 4, borderRadius: "var(--r-md)", background: "var(--bg-neutral)", border: "1px solid var(--line-alt)" },
  },
    AI_PROVIDERS.map((p) => {
      const active = value === p.key;
      return React.createElement("button", {
        key: p.key,
        type: "button",
        role: "tab",
        "aria-selected": active,
        onClick: disabled ? undefined : () => { if (!active) onChange(p.key); },
        disabled,
        style: {
          flex: 1, height: 36, padding: "0 12px", borderRadius: "var(--r-sm)", cursor: disabled ? "default" : "pointer",
          border: active ? "1px solid var(--primary)" : "1px solid transparent",
          background: active ? "var(--bg-normal)" : "transparent",
          color: active ? "var(--primary)" : "var(--label-alt)",
          fontSize: 13.5, fontWeight: 700, fontFamily: "var(--font)",
          transition: "background var(--t-fast), border-color var(--t-fast), color var(--t-fast)",
          opacity: disabled ? 0.6 : 1,
        },
      }, p.label);
    })
  );
}

/* ── 키 행: 상태 배지 + maskedKey + 비밀번호 입력 + 저장/삭제 ──
   각 행은 자기 프로바이더의 독립 draft 만 다룬다. provider 별로 onDraft/onSave/onRemove
   가 격리되어 한 입력창에 타이핑해도 다른 프로바이더 입력창은 영향받지 않는다. */
function AiKeyRow({ provider, info, draft, onDraft, onSave, onRemove, saving, removing, busy }) {
  const meta = providerMeta(provider);
  const can = !!(draft && draft.trim());
  return React.createElement("div", {
    style: { display: "flex", flexDirection: "column", gap: 10, padding: "14px 14px", borderRadius: "var(--r-md)", background: "var(--bg-neutral)", border: "1px solid var(--line-alt)" },
  },
    /* 헤더: 프로바이더명 + 상태 */
    React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8 } },
      React.createElement("span", { className: "t-label-1", style: { color: "var(--label-neutral)", fontWeight: 700 } }, meta.label),
      React.createElement("span", { style: { marginLeft: "auto", display: "inline-flex", alignItems: "center", gap: 8 } },
        info.configured
          ? React.createElement(React.Fragment, null,
              React.createElement(Pill, { color: "var(--positive)", bg: "var(--positive-bg)" },
                React.createElement("span", { style: { width: 6, height: 6, borderRadius: "50%", background: "var(--positive)" } }),
                "등록됨"),
              info.maskedKey ? React.createElement("span", { className: "t-label-2", style: { color: "var(--label-neutral)", fontWeight: 700, maxWidth: 150, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", fontFamily: "var(--font-mono, var(--font))" } }, info.maskedKey) : null)
          : React.createElement(Pill, { color: "var(--label-alt)", bg: "var(--bg-alt)" },
              React.createElement("span", { style: { width: 6, height: 6, borderRadius: "50%", background: "var(--label-assist)" } }),
              "미등록"))),

    /* 입력 + 버튼 */
    React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8 } },
      React.createElement("input", {
        type: "password",
        value: draft || "",
        onChange: (e) => onDraft(e.target.value),
        placeholder: info.configured ? "새 키로 교체하려면 입력해요" : meta.placeholder,
        autoComplete: "off",
        disabled: busy,
        onKeyDown: (e) => { if (e.key === "Enter") { e.preventDefault(); if (can) onSave(); } },
        style: {
          flex: 1, height: 40, padding: "0 12px", borderRadius: "var(--r-sm)",
          border: "1px solid var(--border)", background: "var(--bg-normal)", color: "var(--label-normal)",
          fontSize: 14, fontFamily: "var(--font)", outline: "none",
        },
        onFocus: (e) => { e.target.style.borderColor = "var(--primary)"; },
        onBlur: (e) => { e.target.style.borderColor = "var(--border)"; },
      }),
      React.createElement(Button, { size: "sm", onClick: onSave, disabled: busy || !can },
        saving ? React.createElement(React.Fragment, null, React.createElement(Spinner, { s: 13, color: "#fff" }), "저장 중") : "저장"),
      info.configured ? React.createElement(Button, { size: "sm", kind: "danger", onClick: onRemove, disabled: busy },
        removing ? React.createElement(React.Fragment, null, React.createElement(Spinner, { s: 13, color: "#fff" }), "비우는 중") : "비우기") : null)
  );
}

/* ── 모델 선택(활성 provider 모델 목록 + 직접 입력) ── */
function AiModelPicker({ provider, models, model, onPick, disabled }) {
  // 현재 model 이 목록에 없으면 "직접 입력" 모드
  const inList = models.indexOf(model) !== -1;
  const [custom, setCustom] = useState(!inList && !!model);
  const [customVal, setCustomVal] = useState(inList ? "" : (model || ""));

  // provider/model 변경 시 모드 동기화
  useEffect(() => {
    const has = models.indexOf(model) !== -1;
    setCustom(!has && !!model);
    setCustomVal(has ? "" : (model || ""));
  }, [provider, model, models.join("|")]);

  const selectVal = custom ? DIRECT_MODEL : (inList ? model : DIRECT_MODEL);

  function onSelect(e) {
    const v = e.target.value;
    if (v === DIRECT_MODEL) {
      setCustom(true);
      setCustomVal(model && models.indexOf(model) === -1 ? model : "");
    } else {
      setCustom(false);
      onPick(v);
    }
  }
  function commitCustom() {
    const v = (customVal || "").trim();
    if (v && v !== model) onPick(v);
  }

  return React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 8 } },
    React.createElement("span", { className: "t-label-2", style: { color: "var(--label-neutral)", fontWeight: 700 } }, "모델"),
    React.createElement("div", { style: { position: "relative", display: "flex", alignItems: "center" } },
      React.createElement("select", {
        value: selectVal,
        onChange: onSelect,
        disabled,
        style: {
          width: "100%", height: 40, padding: "0 36px 0 12px", borderRadius: "var(--r-sm)",
          border: "1px solid var(--border)", background: "var(--bg-normal)", color: "var(--label-normal)",
          fontSize: 14, fontFamily: "var(--font)", outline: "none", cursor: disabled ? "default" : "pointer",
          appearance: "none", WebkitAppearance: "none", MozAppearance: "none",
        },
      },
        models.map((m) => React.createElement("option", { key: m, value: m }, m)),
        React.createElement("option", { key: DIRECT_MODEL, value: DIRECT_MODEL }, "직접 입력")),
      React.createElement("svg", {
        width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "var(--label-alt)", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round",
        style: { position: "absolute", right: 12, pointerEvents: "none" },
      }, React.createElement("path", { d: "M6 9l6 6 6-6" }))),
    custom ? React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8 } },
      React.createElement("input", {
        type: "text",
        value: customVal,
        onChange: (e) => setCustomVal(e.target.value),
        placeholder: "모델 id 직접 입력 (예: " + (models[0] || "gpt-...") + ")",
        autoComplete: "off",
        disabled,
        onKeyDown: (e) => { if (e.key === "Enter") { e.preventDefault(); commitCustom(); } },
        style: {
          flex: 1, height: 40, padding: "0 12px", borderRadius: "var(--r-sm)",
          border: "1px solid var(--border)", background: "var(--bg-normal)", color: "var(--label-normal)",
          fontSize: 14, fontFamily: "var(--font-mono, var(--font))", outline: "none",
        },
        onFocus: (e) => { e.target.style.borderColor = "var(--primary)"; },
        onBlur: (e) => { e.target.style.borderColor = "var(--border)"; },
      }),
      React.createElement(Button, { size: "sm", kind: "outline", onClick: commitCustom, disabled: disabled || !customVal.trim() || customVal.trim() === model }, "적용")) : null,
    React.createElement("span", { className: "t-caption-1", style: { color: "var(--label-assist)" } }, "모델 id는 바뀔 수 있어요. 목록에 없으면 직접 입력해서 적용해요.")
  );
}

/* ── AI 설정 패널 ──
   모달 껍데기 없이 본문만 렌더(관리자 페이지 "API관리" 탭에서 사용).
   props: 없음 */
function AiSettingsPanel() {
  const [loading, setLoading] = useState(true);   // 최초 조회 로딩
  const [state, setState] = useState(null);       // 정규화된 GET shape
  // 프로바이더별 독립 draft — openai/gemini 입력이 서로 영향 주지 않도록 분리한다.
  const [drafts, setDrafts] = useState({ openai: "", gemini: "" }); // 키 입력값(저장 후 해당 키만 비움)
  const [savingKey, setSavingKey] = useState("");  // "openai"|"gemini" 저장중
  const [removingKey, setRemovingKey] = useState(""); // "openai"|"gemini" 비우는중
  const [switching, setSwitching] = useState(false); // provider 전환중
  const [modelSaving, setModelSaving] = useState(false);
  const [loadErr, setLoadErr] = useState("");      // 조회 실패(403 등)
  const [err, setErr] = useState("");              // 저장/삭제 실패
  const [note, setNote] = useState("");            // 해요체 완료 안내

  const load = useCallback(async () => {
    setLoadErr("");
    try {
      const data = await api("/settings/ai");   // GET
      setState(normAiSettings(data));
    } catch (ex) {
      setLoadErr((ex && ex.message) || "설정을 불러오지 못했어요.");
    } finally {
      setLoading(false);
    }
  }, []);
  useEffect(() => { load(); }, [load]);

  const busy = !!savingKey || !!removingKey || switching || modelSaving;

  /* 공통 PUT — 부분 업데이트, 응답으로 state 동기화 */
  async function putAi(body) {
    const data = await api("/settings/ai", { method: "PUT", body });
    setState(normAiSettings(data));
    return data;
  }

  /* 프로바이더 전환 */
  async function switchProvider(next) {
    if (busy || !state || state.provider === next) return;
    setErr(""); setNote(""); setSwitching(true);
    try {
      // 전환 대상 provider 의 현재 model 이 목록에 있으면 유지, 아니면 기본 model 채택
      const list = (state.models[next] || []);
      const keep = list.indexOf(state.model) !== -1 ? state.model : (list[0] || state.model);
      const body = { provider: next };
      if (keep) body.model = keep;
      await putAi(body);
      setNote(providerMeta(next).label + " 로 전환했어요.");
    } catch (ex) {
      setErr((ex && ex.message) || "프로바이더를 전환하지 못했어요.");
    } finally {
      setSwitching(false);
    }
  }

  /* 모델 변경 */
  async function pickModel(m) {
    if (busy || !state || state.model === m) return;
    setErr(""); setNote(""); setModelSaving(true);
    try {
      await putAi({ model: m });
      setNote("모델을 " + m + " 로 바꿨어요.");
    } catch (ex) {
      setErr((ex && ex.message) || "모델을 바꾸지 못했어요.");
    } finally {
      setModelSaving(false);
    }
  }

  /* 키 저장 — 해당 프로바이더의 draft 만 PUT, 성공 시 그 프로바이더 draft 만 비움 */
  async function saveKey(provider) {
    const meta = providerMeta(provider);
    const key = (drafts[provider] || "").trim();
    if (!key) { setErr(meta.label + " 키를 입력해 주세요."); return; }
    setErr(""); setNote(""); setSavingKey(provider);
    try {
      await putAi({ [meta.keyField]: key });
      setDrafts((d) => ({ ...d, [provider]: "" }));  // ★ 해당 프로바이더 키만 비워요(다른 입력은 유지)
      setNote(meta.label + " 키를 저장했어요.");
    } catch (ex) {
      setErr((ex && ex.message) || "키를 저장하지 못했어요.");
    } finally {
      setSavingKey("");
    }
  }

  /* 키 비우기(삭제) — 해당 프로바이더만 */
  async function removeKey(provider) {
    const meta = providerMeta(provider);
    if (busy) return;
    if (typeof window !== "undefined" && typeof window.confirm === "function") {
      const ok = window.confirm(meta.label + " 키를 비울까요? 비우면 이 프로바이더로는 원고 파싱이 안 돼요.");
      if (!ok) return;
    }
    setErr(""); setNote(""); setRemovingKey(provider);
    try {
      await putAi({ [meta.keyField]: "" });  // ★ 빈 문자열 -> 키 삭제
      setDrafts((d) => ({ ...d, [provider]: "" }));
      setNote(meta.label + " 키를 비웠어요.");
    } catch (ex) {
      setErr((ex && ex.message) || "키를 비우지 못했어요.");
    } finally {
      setRemovingKey("");
    }
  }

  // 본문(로딩/조회실패/정상)
  let bodyEls;
  if (loading) {
    bodyEls = [React.createElement("div", { key: "load", style: { display: "flex", alignItems: "center", gap: 9, padding: "8px 2px" } },
      React.createElement(Spinner, { s: 16 }),
      React.createElement("span", { className: "t-caption-1", style: { color: "var(--label-alt)" } }, "설정을 불러오는 중이에요"))];
  } else if (loadErr) {
    bodyEls = [React.createElement("div", { key: "loaderr", style: { display: "flex", flexDirection: "column", gap: 8, padding: "12px 14px", borderRadius: "var(--r-sm)", background: "var(--negative-bg)", border: "1px solid var(--negative)" } },
      React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 7 } },
        React.createElement("svg", { width: 15, height: 15, viewBox: "0 0 24 24", fill: "none", stroke: "var(--negative)", strokeWidth: 2.2, strokeLinecap: "round", strokeLinejoin: "round" }, React.createElement("circle", { cx: 12, cy: 12, r: 10 }), React.createElement("path", { d: "M12 8v4M12 16h.01" })),
        React.createElement("span", { className: "t-label-1", style: { color: "var(--negative)" } }, "설정을 열 수 없어요")),
      React.createElement("p", { className: "t-label-2", style: { color: "var(--label-neutral)", margin: 0, lineHeight: 1.6, whiteSpace: "pre-wrap" } }, loadErr))];
  } else if (state) {
    const activeMeta = providerMeta(state.provider);
    bodyEls = [
      /* 1) 프로바이더 선택 */
      React.createElement("div", { key: "prov", style: { display: "flex", flexDirection: "column", gap: 8 } },
        React.createElement("span", { className: "t-label-2", style: { color: "var(--label-neutral)", fontWeight: 700 } }, "사용할 AI"),
        React.createElement(ProviderSegment, { value: state.provider, onChange: switchProvider, disabled: busy }),
        switching ? React.createElement("span", { className: "t-caption-1", style: { color: "var(--label-alt)", display: "inline-flex", alignItems: "center", gap: 6 } },
          React.createElement(Spinner, { s: 12 }), "전환 중이에요") : null),

      /* 2) 모델 선택(활성 provider) */
      React.createElement("div", { key: "model", style: { display: "flex", flexDirection: "column", gap: 8 } },
        React.createElement(AiModelPicker, {
          provider: state.provider,
          models: state.models[state.provider] || [],
          model: state.model,
          onPick: pickModel,
          disabled: busy,
        }),
        modelSaving ? React.createElement("span", { className: "t-caption-1", style: { color: "var(--label-alt)", display: "inline-flex", alignItems: "center", gap: 6 } },
          React.createElement(Spinner, { s: 12 }), "모델을 저장하는 중이에요") : null),

      /* 3) 키 입력 2개 — 프로바이더별 독립 draft (서로 영향 없음) */
      React.createElement("div", { key: "keys", style: { display: "flex", flexDirection: "column", gap: 10 } },
        React.createElement("span", { className: "t-label-2", style: { color: "var(--label-neutral)", fontWeight: 700 } }, "API 키"),
        ...AI_PROVIDERS.map((p) => React.createElement(AiKeyRow, {
          key: p.key,
          provider: p.key,
          info: state[p.key],
          draft: drafts[p.key],
          onDraft: (v) => { setDrafts((d) => ({ ...d, [p.key]: v })); if (err) setErr(""); },
          onSave: () => saveKey(p.key),
          onRemove: () => removeKey(p.key),
          saving: savingKey === p.key,
          removing: removingKey === p.key,
          busy,
        })),
        React.createElement("span", { className: "t-caption-1", style: { color: "var(--label-assist)" } }, "두 키를 모두 보관하니 프로바이더를 바꿔도 키를 다시 넣지 않아도 돼요.")),

      /* 완료/오류 안내 */
      note ? React.createElement("div", { key: "note", className: "t-label-2", style: { color: "var(--positive)", background: "var(--positive-bg)", borderRadius: "var(--r-sm)", padding: "10px 14px", display: "flex", alignItems: "center", gap: 8 } },
        React.createElement("svg", { width: 15, height: 15, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.4, strokeLinecap: "round", strokeLinejoin: "round" }, React.createElement("path", { d: "M20 6 9 17l-5-5" })),
        note) : null,
      err ? React.createElement("div", { key: "err", className: "t-label-2", style: { color: "var(--negative)", background: "var(--negative-bg)", borderRadius: "var(--r-sm)", padding: "10px 14px" } }, err) : null,

      /* 안내문(해요체) */
      React.createElement("div", { key: "help", style: { display: "flex", flexDirection: "column", gap: 6, padding: "12px 14px", borderRadius: "var(--r-md)", background: "var(--info-bg)", border: "1px solid var(--line-alt)" } },
        React.createElement("p", { className: "t-caption-1", style: { color: "var(--label-neutral)", margin: 0, lineHeight: 1.6 } }, "키를 넣으면 원고 PDF를 올렸을 때 선택한 AI가 스토리보드를 자동으로 만들어요. 키는 서버에 안전하게 저장되고, 화면에는 일부만 보여요."),
        React.createElement("p", { className: "t-caption-1", style: { color: "var(--label-alt)", margin: 0, lineHeight: 1.6 } }, "ChatGPT(OpenAI) 키는 platform.openai.com, Gemini(Google) 키는 aistudio.google.com/apikey 에서 발급할 수 있어요."))
    ];
  } else {
    bodyEls = [];
  }

  return React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 16, maxWidth: 620 } },
    React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 4 } },
      React.createElement("div", { className: "t-title-3", style: { color: "var(--label-normal)" } }, "AI 원고 파싱"),
      React.createElement("p", { className: "t-body-2", style: { color: "var(--label-alt)", margin: 0 } }, "원고를 자동으로 스토리보드로 만드는 AI 프로바이더와 키를 관리해요.")),
    ...bodyEls
  );
}

Object.assign(window, { AiSettingsPanel, ProviderSegment, AiKeyRow, AiModelPicker, AI_PROVIDERS });
