<!doctype html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <%- include('partials/favicon') %>
    <title>AI 활용 사례 &gt; 작성하기 - NCue</title>
    <link rel="stylesheet" href="https://uicdn.toast.com/editor/3.2.2/toastui-editor.min.css" />
    <link rel="stylesheet" href="/public/styles.css" />
  </head>
  <body>
    <div class="app-shell">
      <%- include('partials/nav', { activeMenu: 'ai-cases' }) %>
      <div class="content-area">
        <header class="topbar">
          <h1>AI 활용 사례 &gt; <%= editPayload ? "수정" : "작성" %></h1>
          <a class="top-action-link top-action-link--ghost" href="/ai-cases">목록</a>
        </header>
        <main class="container container-narrow use-case-compose">
          <p class="use-case-compose__hint">
            <strong>작성자: </strong> <%= typeof submitterEmail !== "undefined" ? submitterEmail : "" %>
          </p>
          <form id="use-case-form" class="use-case-compose__form" novalidate>
            <div class="use-case-field">
              <label for="uctitle">제목 <span class="req">*</span></label>
              <input
                type="text"
                id="uctitle"
                name="title"
                class="use-case-title-input"
                required
                maxlength="200"
                placeholder="제목을 입력하세요"
                autocomplete="off"
                autofocus
              />
            </div>
            <div class="use-case-section use-case-section--rich use-case-section--merged">
              <label class="label-block" for="edUseCaseBody">본문 (STAR: 1~4번) <span class="req">*</span></label>
              <p class="field-hint use-case-merge-hint">한 편집기 안에서 1.Situation → 4.Result 순서로 작성합니다.<br>구역을 나누는 제목·블록을 삭제하면 저장이 실패할 수 있습니다.</p>
              <div id="edUseCaseBody" class="use-case-editor-host use-case-editor-host--merged" aria-label="STAR 본문"></div>
            </div>
            <p class="use-case-charcount" id="ucCharLine" aria-live="polite">0 / <%= maxBodyTotal %>자</p>
            <div class="use-case-compose__meta">
            <div class="use-case-field use-case-field--tags">
              <label for="uctags">활용 AI</label>
              <input
                type="text"
                id="uctags"
                name="tags"
                class="use-case-tag-input"
                placeholder="쉼표로 구분 (예, Claude, Slack, Canvas)"
                autocomplete="off"
              />
              <p class="field-hint">활용한 AI 툴을 입력해주세요.</p>
            </div>
            <div class="use-case-field" id="ucThumbField">
              <span class="label-block">썸네일 이미지 <% if (!editPayload) { %><span class="req">*</span><% } else { %><span class="opt">(변경·추가 시에만)</span><% } %></span>
              <p class="field-hint" id="ucThumbFieldHint">최대 <%= maxThumbCount %>개, 개당 5MB, 가급 1:1 비율 권장</p>
              <% if (typeof editPayload !== "undefined" && editPayload) { %>
              <p class="field-hint use-case-attach-hint">이미지 우측 상단 <strong>X</strong>로 삭제할 수 있습니다. 새 이미지는 아래에서 고르면 목록 끝에 추가됩니다(합계 최대 <%= maxThumbCount %>개).</p>
              <% } %>
              <div class="use-case-dropzone" id="ucThumbZone">
                <input type="file" id="ucThumb" name="thumbnail" accept="image/*" class="use-case-file-input" multiple />
                <label for="ucThumb" class="use-case-dropzone__label"
                  >클릭하거나 드래그하여 썸네일을 선택하세요 (최대 <%= maxThumbCount %>개)</label
                >
              </div>
              <div class="use-case-thumb-grid" id="ucThumbPreviewGrid" hidden>
                <% if (typeof editPayload !== "undefined" && editPayload && editPayload.existingThumbnails && editPayload.existingThumbnails.length) { %>
                <% editPayload.existingThumbnails.forEach(function (t) { var fn = (t.originalName || "썸네일").replace(/[<>"]/g, "") || (t.relativePath && t.relativePath.split("/").pop()) || "썸네일"; %>
                <figure class="use-case-thumb-tile" data-existing-rp="<%- encodeURIComponent(t.relativePath) %>">
                  <img src="<%= t.relativePath %>" alt="<%= fn %>" loading="lazy" decoding="async" />
                  <button type="button" class="use-case-thumb-remove" aria-label="<%= fn %> 제거" title="제거">×</button>
                </figure>
                <% }); %>
                <% } %>
              </div>
            </div>
            <div class="use-case-field">
              <span class="label-block">첨부 파일 <span class="opt">(선택, 최대 <%= maxAttachCount %>개·20MB)</span></span>
              <% if (typeof editPayload !== "undefined" && editPayload) { %>
              <p class="field-hint use-case-attach-hint">수정 시: 아래 <strong>기존 첨부</strong>를 체크해 삭제한 뒤 새 파일을 선택할 수 있습니다(최대 <%= maxAttachCount %>개).</p>
              <% } %>
              <input type="file" id="ucFiles" name="attachments" class="use-case-file-multi" />
              <% if (typeof editPayload !== "undefined" && editPayload && editPayload.existingAttachments && editPayload.existingAttachments.length) { %>
              <p class="field-hint use-case-existing-attach__title">기존 첨부 — 제거하려면 체크</p>
              <ul class="use-case-existing-attach">
                <% editPayload.existingAttachments.forEach(function (a) { var fn = (a.originalName || "").replace(/[<>"]/g, "") || (a.relativePath && a.relativePath.split("/").pop()) || "첨부"; %>
                <li>
                  <label class="use-case-cb"
                    ><input type="checkbox" class="js-uc-remove-attach" data-rp="<%- encodeURIComponent(a.relativePath) %>" /> <%= fn %></label
                  >
                </li>
                <% }); %>
              </ul>
              <% } %>
              <ul class="use-case-file-list" id="ucFileList" hidden></ul>
            </div>
            </div>
            <div class="use-case-actions">
              <a href="/ai-cases" class="btn-ghost use-case-btn-cancel">취소</a>
              <button type="submit" class="top-action use-case-btn-save" id="ucSubmit"><%= editPayload ? "수정 저장" : "저장하기" %></button>
            </div>
            <p class="form-message use-case-form-msg" id="ucFormMsg" hidden></p>
            <% if (editPayload) { %>
            <script type="application/json" id="uc-edit-json">
              <%- JSON.stringify(editPayload).replace(/</g, "\\u003c") %>
            </script>
            <% } %>
          </form>
        </main>
      </div>
    </div>
    <script src="https://uicdn.toast.com/editor/3.2.2/toastui-editor-all.min.js"></script>
    <script src="https://uicdn.toast.com/editor/3.2.2/i18n/ko-kr.min.js"></script>
    <script>
      (function () {
        var maxTotal = <%= maxBodyTotal %>;
        var maxThumbCount = <%= maxThumbCount %>;
        var maxAttachCount = <%= maxAttachCount %>;
        var ph = {
          situation: <%- JSON.stringify(placeholders.situation) %>,
          task: <%- JSON.stringify(placeholders.task) %>,
          action: <%- JSON.stringify(placeholders.action) %>,
          result: <%- JSON.stringify(placeholders.result) %>,
        };
        var charLine = document.getElementById("ucCharLine");
        var editJson = document.getElementById("uc-edit-json");
        var editPayload = null;
        if (editJson) {
          try {
            editPayload = JSON.parse(editJson.textContent);
          } catch (e) {
            editPayload = null;
          }
        }
        var form = document.getElementById("use-case-form");
        var msg = document.getElementById("ucFormMsg");
        var submitBtn = document.getElementById("ucSubmit");
        var thumb = document.getElementById("ucThumb");
        var thumbGrid = document.getElementById("ucThumbPreviewGrid");
        var pendingThumbFiles = [];
        var pendingThumbUrls = [];
        var filesIn = document.getElementById("ucFiles");
        var fileList = document.getElementById("ucFileList");
        var sectionIds = ["uc-situation", "uc-task", "uc-action", "uc-result"];
        var fieldKeys = ["situation", "taskGoal", "actionTaken", "resultOutcome"];
        var phKeysByField = {
          situation: "situation",
          taskGoal: "task",
          actionTaken: "action",
          resultOutcome: "result",
        };
        var placeholdersActive = !editPayload;
        var examplesComposeMode = !editPayload;
        if (typeof toastui === "undefined" || !toastui.Editor) {
          if (form) {
            var p = document.createElement("p");
            p.className = "form-message use-case-form-msg";
            p.style.color = "#b91c1c";
            p.textContent = "에디터를 불러오지 못했습니다. 네트워크·방화벽을 확인하거나 uicdn.toast.com 접속을 허용해 주세요.";
            form.insertBefore(p, form.firstChild);
          }
          return;
        }
        function esc(s) {
          if (s == null) return "";
          return String(s)
            .replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;")
            .replace(/"/g, "&quot;")
            .replace(/'/g, "&#39;");
        }
        function paraFromPh(text) {
          if (!text) return "<p><br></p>";
          return (
            '<p class="uc-example-text" data-uc-example="1">' +
            esc(text).replace(/\r\n/g, "\n").split("\n").join("<br>") +
            "</p>"
          );
        }
        function buildHtmlFromSections(sec) {
          sec = sec || {};
          return (
            '<div class="uc-doc">' +
            '<div id="uc-situation" class="uc-section"><h2>1. Situation (배경)</h2>' +
            (sec.situation || "<p><br></p>") +
            "</div>" +
            '<div id="uc-task" class="uc-section"><h2>2. Task (과제/목표)</h2>' +
            (sec.taskGoal || "<p><br></p>") +
            "</div>" +
            '<div id="uc-action" class="uc-section"><h2>3. Action (행동)</h2>' +
            (sec.actionTaken || "<p><br></p>") +
            "</div>" +
            '<div id="uc-result" class="uc-section"><h2>4. Result (결과)</h2>' +
            (sec.resultOutcome || "<p><br></p>") +
            "</div>" +
            "</div>"
          );
        }
        function buildInitialHtml() {
          return buildHtmlFromSections({
            situation: paraFromPh(ph.situation),
            taskGoal: paraFromPh(ph.task),
            actionTaken: paraFromPh(ph.action),
            resultOutcome: paraFromPh(ph.result),
          });
        }
        function normalizePlain(s) {
          return String(s || "")
            .replace(/\s+/g, " ")
            .trim();
        }
        function isPlaceholderBody(html, phKey) {
          var phPlain = normalizePlain(ph[phKey]);
          if (!phPlain) return false;
          return normalizePlain(stripForCount(html)) === phPlain;
        }
        function sectionHasExampleMarker(html) {
          return /uc-example-text|data-uc-example/.test(String(html || ""));
        }
        function isSectionBodyEmpty(html) {
          return stripForCount(html).length === 0;
        }
        function hasUserBodyInput() {
          var ex = extractSections(editor.getHTML());
          for (var i = 0; i < fieldKeys.length; i++) {
            var body = ex[fieldKeys[i]] || "";
            if (sectionHasExampleMarker(body)) return false;
            if (!isSectionBodyEmpty(body) && !isPlaceholderBody(body, phKeysByField[fieldKeys[i]])) {
              return true;
            }
          }
          return false;
        }
        function restoreExamplesIfEmptyDraft() {
          if (!examplesComposeMode || placeholdersActive) return;
          if (hasUserBodyInput()) return;
          placeholdersActive = true;
          editor.setHTML(buildInitialHtml());
          count();
        }
        /** 본문 영역 첫 클릭 시 STAR 1~4 예시 문단만 제거(제목은 유지) */
        function clearExampleContentOnActivate() {
          if (!placeholdersActive) return;
          placeholdersActive = false;
          var empty = "<p><br></p>";
          var wrapper = document.createElement("div");
          wrapper.innerHTML = editor.getHTML();
          var clearedById = false;
          for (var i = 0; i < sectionIds.length; i++) {
            var sec = wrapper.querySelector("#" + sectionIds[i]);
            if (!sec) continue;
            var head = sec.querySelector(":scope > h1, :scope > h2, :scope > h3, :scope > h4");
            sec.innerHTML = (head ? head.outerHTML : "") + empty;
            clearedById = true;
          }
          setTimeout(function () {
            if (clearedById) {
              editor.setHTML(wrapper.innerHTML);
            } else {
              editor.setHTML(
                buildHtmlFromSections({
                  situation: empty,
                  taskGoal: empty,
                  actionTaken: empty,
                  resultOutcome: empty,
                })
              );
            }
            count();
          }, 0);
        }
        /** @returns {{ situation: string, taskGoal: string, actionTaken: string, resultOutcome: string, ok: boolean, err?: string }} */
        function extractSections(html) {
          var out = { situation: "", taskGoal: "", actionTaken: "", resultOutcome: "", ok: true };
          var w = document.createElement("div");
          w.innerHTML = html;
          var got = 0;
          for (var i = 0; i < sectionIds.length; i++) {
            var sec = w.querySelector("#" + sectionIds[i]);
            if (sec) {
              var c = sec.cloneNode(true);
              var hx = c.querySelector(":scope > h1, :scope > h2, :scope > h3, :scope > h4");
              if (hx) hx.remove();
              out[fieldKeys[i]] = c.innerHTML.trim();
              got++;
            }
          }
          if (got === 4) {
            out.ok = true;
            return out;
          }
          var byH = extractByHeadings(w);
          if (byH) {
            byH.ok = true;
            return byH;
          }
          return { situation: out.situation, taskGoal: out.taskGoal, actionTaken: out.actionTaken, resultOutcome: out.resultOutcome, ok: false, err: "split" };
        }
        function extractByHeadings(wrap) {
          var patterns = [
            { key: "situation", re: /1\.\s*Situation/i },
            { key: "taskGoal", re: /2\.\s*Task/i },
            { key: "actionTaken", re: /3\.\s*Action/i },
            { key: "resultOutcome", re: /4\.\s*Result/i },
          ];
          var heads = wrap.querySelectorAll("h1, h2, h3, h4");
          var found = [];
          for (var h = 0; h < heads.length; h++) {
            var t = (heads[h].textContent || "").replace(/\s+/g, " ").trim();
            for (var p = 0; p < patterns.length; p++) {
              if (patterns[p].re.test(t)) {
                found.push({ key: patterns[p].key, el: heads[h] });
                break;
              }
            }
          }
          if (found.length < 4) {
            return null;
          }
          var seen = {};
          for (var f = 0; f < found.length; f++) {
            if (seen[found[f].key]) return null;
            seen[found[f].key] = true;
          }
          if (Object.keys(seen).length !== 4) return null;
          found.sort(function (a, b) {
            var po = a.el.compareDocumentPosition(b.el);
            if (po & Node.DOCUMENT_POSITION_FOLLOWING) return -1;
            if (po & Node.DOCUMENT_POSITION_PRECEDING) return 1;
            return 0;
          });
          var res = { situation: "", taskGoal: "", actionTaken: "", resultOutcome: "" };
          for (var s = 0; s < found.length; s++) {
            var head = found[s].el;
            var boundary = s + 1 < found.length ? found[s + 1].el : null;
            var n = head.nextSibling;
            var parts = [];
            while (n) {
              if (boundary && n === boundary) break;
              if (n.nodeType === 1) {
                parts.push(n.outerHTML);
              }
              n = n.nextSibling;
            }
            res[found[s].key] = parts.join("").trim();
          }
          return res;
        }
        function stripForCount(html) {
          if (!html) return "";
          return String(html)
            .replace(/<style[\s\S]*?<\/style>/gi, " ")
            .replace(/<script[\s\S]*?<\/script>/gi, " ")
            .replace(/<[^>]+>/g, " ")
            .replace(/&nbsp;/g, " ")
            .replace(/&#[0-9]+;/g, " ")
            .replace(/&[a-zA-Z0-9]+;/g, " ")
            .replace(/\s+/g, " ")
            .trim();
        }
        var edHost = document.getElementById("edUseCaseBody");
        var editor = new toastui.Editor({
          el: edHost,
          height: "720px",
          initialEditType: "wysiwyg",
          previewStyle: "vertical",
          hideModeSwitch: true,
          useCommandShortcut: true,
          usageStatistics: false,
          language: "ko",
          placeholder: "STAR 4구역(1~4번)이 보이지 않으면 페이지를 새로고침하세요.",
          toolbarItems: [
            ["heading", "bold", "italic", "strike"],
            ["hr", "quote"],
            ["ul", "ol", "task", "indent", "outdent"],
            ["table", "link"],
            ["code", "codeblock"],
          ],
        });
        if (editPayload && editPayload.html) {
          document.getElementById("uctitle").value = editPayload.title || "";
          document.getElementById("uctags").value = editPayload.tags || "";
          editor.setHTML(editPayload.html);
          if (editPayload.existingThumbnails && editPayload.existingThumbnails.length) {
            var h = document.getElementById("ucThumbFieldHint");
            if (h) h.textContent = "새로 선택하면 목록 끝에 추가됩니다. (최대 " + maxThumbCount + "개, 개당 5MB, 1:1 권장)";
            if (thumbGrid) thumbGrid.hidden = false;
          }
        } else {
          editor.setHTML(buildInitialHtml());
        }
        var titleInput = document.getElementById("uctitle");
        function focusTitleInput() {
          if (titleInput) titleInput.focus({ preventScroll: true });
        }
        if (examplesComposeMode) {
          edHost.addEventListener(
            "mousedown",
            function (ev) {
              if (!placeholdersActive || ev.button !== 0) return;
              if (!ev.target.closest(".toastui-editor-contents")) return;
              clearExampleContentOnActivate();
            },
            true
          );
          document.addEventListener(
            "mousedown",
            function (ev) {
              if (ev.button !== 0 || placeholdersActive) return;
              if (edHost.contains(ev.target)) return;
              restoreExamplesIfEmptyDraft();
            },
            true
          );
        }
        focusTitleInput();
        setTimeout(focusTitleInput, 0);
        setTimeout(focusTitleInput, 100);
        function count() {
          var ex = extractSections(editor.getHTML());
          var n = 0;
          for (var i = 0; i < fieldKeys.length; i++) {
            n += stripForCount(ex[fieldKeys[i]] || "").length;
          }
          if (charLine) {
            charLine.textContent = n + " / " + maxTotal + "자";
          }
          return n;
        }
        editor.on("change", function () {
          count();
        });
        count();
        function countKeptExistingThumbs() {
          if (!thumbGrid) return 0;
          return thumbGrid.querySelectorAll(".use-case-thumb-tile[data-existing-rp]:not(.is-removed)").length;
        }
        function countPendingThumbs() {
          return pendingThumbFiles.length;
        }
        function countRemainingThumbsOnSubmit() {
          return countKeptExistingThumbs() + countPendingThumbs();
        }
        function revokePendingThumbUrls() {
          for (var ui = 0; ui < pendingThumbUrls.length; ui++) {
            try {
              URL.revokeObjectURL(pendingThumbUrls[ui]);
            } catch (e) {}
          }
          pendingThumbUrls = [];
        }
        function updateThumbGridVisibility() {
          if (!thumbGrid) return;
          var visible =
            thumbGrid.querySelectorAll(".use-case-thumb-tile:not(.is-removed)").length > 0 ||
            countPendingThumbs() > 0;
          thumbGrid.hidden = !visible;
        }
        function renderPendingThumbTiles() {
          if (!thumbGrid) return;
          var oldPending = thumbGrid.querySelectorAll(".use-case-thumb-tile[data-pending-index]");
          for (var oi = 0; oi < oldPending.length; oi++) {
            oldPending[oi].remove();
          }
          revokePendingThumbUrls();
          for (var pi = 0; pi < pendingThumbFiles.length; pi++) {
            var file = pendingThumbFiles[pi];
            var url = URL.createObjectURL(file);
            pendingThumbUrls.push(url);
            var fig = document.createElement("figure");
            fig.className = "use-case-thumb-tile";
            fig.setAttribute("data-pending-index", String(pi));
            var img = document.createElement("img");
            img.src = url;
            img.alt = file.name || "썸네일";
            img.loading = "lazy";
            img.decoding = "async";
            var btn = document.createElement("button");
            btn.type = "button";
            btn.className = "use-case-thumb-remove";
            btn.setAttribute("aria-label", (file.name || "썸네일") + " 제거");
            btn.title = "제거";
            btn.textContent = "×";
            fig.appendChild(img);
            fig.appendChild(btn);
            thumbGrid.appendChild(fig);
          }
          updateThumbGridVisibility();
        }
        function notifyThumbLimitPopup(addedCount, selectedCount) {
          var base = "썸네일은 최대 " + maxThumbCount + "개까지 업로드할 수 있습니다.";
          if (typeof addedCount === "number" && typeof selectedCount === "number" && selectedCount > addedCount && addedCount > 0) {
            window.alert(base + "\n\n선택하신 " + selectedCount + "개 중 " + addedCount + "개만 추가되었습니다.");
            return;
          }
          if (typeof addedCount === "number" && addedCount === 0) {
            window.alert(base + "\n\n더 이상 추가할 수 없습니다. 기존 썸네일을 삭제한 뒤 다시 선택해 주세요.");
            return;
          }
          window.alert(base);
        }
        function addPendingThumbFiles(fileList) {
          if (!fileList || !fileList.length) return true;
          var keptExisting = countKeptExistingThumbs();
          var remaining = maxThumbCount - keptExisting - pendingThumbFiles.length;
          if (remaining <= 0) {
            notifyThumbLimitPopup(0, fileList.length);
            return false;
          }
          var selectedCount = fileList.length;
          var addedCount = 0;
          for (var ai = 0; ai < fileList.length; ai++) {
            if (addedCount >= remaining) break;
            var f = fileList[ai];
            if (!/^image\//.test(f.type || "")) {
              msg.textContent = "썸네일은 이미지 파일만 업로드할 수 있습니다.";
              msg.style.color = "#b91c1c";
              msg.hidden = false;
              return false;
            }
            if (f.size > 5 * 1024 * 1024) {
              msg.textContent = '"' + (f.name || "파일") + '"은 5MB 이하여야 합니다.';
              msg.style.color = "#b91c1c";
              msg.hidden = false;
              return false;
            }
            pendingThumbFiles.push(f);
            addedCount++;
          }
          if (selectedCount > remaining) {
            notifyThumbLimitPopup(addedCount, selectedCount);
          }
          msg.hidden = true;
          renderPendingThumbTiles();
          return true;
        }
        if (thumbGrid) {
          thumbGrid.addEventListener("click", function (ev) {
            var btn = ev.target.closest(".use-case-thumb-remove");
            if (!btn) return;
            ev.preventDefault();
            var tile = btn.closest(".use-case-thumb-tile");
            if (!tile) return;
            if (tile.hasAttribute("data-existing-rp")) {
              tile.classList.add("is-removed");
              updateThumbGridVisibility();
              return;
            }
            if (tile.hasAttribute("data-pending-index")) {
              var idx = parseInt(tile.getAttribute("data-pending-index"), 10);
              if (!Number.isNaN(idx) && idx >= 0 && idx < pendingThumbFiles.length) {
                pendingThumbFiles.splice(idx, 1);
                renderPendingThumbTiles();
              }
            }
          });
        }
        if (thumb) {
          thumb.addEventListener("change", function () {
            if (!thumb.files || !thumb.files.length) return;
            addPendingThumbFiles(thumb.files);
            thumb.value = "";
          });
        }
        if (filesIn && fileList) {
          filesIn.addEventListener("change", function () {
            fileList.innerHTML = "";
            if (!filesIn.files || !filesIn.files.length) {
              fileList.hidden = true;
              return;
            }
            if (filesIn.files.length > maxAttachCount) {
              msg.textContent = "첨부 파일은 최대 " + maxAttachCount + "개만 선택할 수 있습니다.";
              msg.style.color = "#b91c1c";
              msg.hidden = false;
              filesIn.value = "";
              fileList.hidden = true;
              return;
            }
            var keptAttach = 0;
            var attachCbs = document.querySelectorAll(".js-uc-remove-attach");
            for (var ai = 0; ai < attachCbs.length; ai++) {
              if (!attachCbs[ai].checked) keptAttach++;
            }
            if (keptAttach + filesIn.files.length > maxAttachCount) {
              msg.textContent =
                "첨부 파일은 최대 " +
                maxAttachCount +
                "개입니다. 기존 첨부를 제거한 뒤 새 파일을 선택해 주세요.";
              msg.style.color = "#b91c1c";
              msg.hidden = false;
              filesIn.value = "";
              fileList.hidden = true;
              return;
            }
            msg.hidden = true;
            fileList.hidden = false;
            for (var k = 0; k < filesIn.files.length; k++) {
              var li = document.createElement("li");
              li.textContent = filesIn.files[k].name;
              fileList.appendChild(li);
            }
          });
        }
        if (form) {
          form.addEventListener("submit", function (ev) {
            ev.preventDefault();
            var ex = extractSections(editor.getHTML());
            if (ex && ex.ok === false) {
              msg.textContent =
                "1~4번 구역(#uc-situation 등)을 찾을 수 없습니다. 구역을 삭제하지 말고, 제목(1. Situation …)이 보이는지 확인해 주세요.";
              msg.style.color = "#b91c1c";
              msg.hidden = false;
              return;
            }
            if (count() > maxTotal) {
              msg.textContent = "본문(4개 섹션 합계)은 " + maxTotal + "자 이하여야 합니다. (보이는 텍스트 기준)";
              msg.style.color = "#b91c1c";
              msg.hidden = false;
              return;
            }
            for (var v = 0; v < fieldKeys.length; v++) {
              var fk = fieldKeys[v];
              var body = ex[fk];
              if (
                isSectionBodyEmpty(body) ||
                isPlaceholderBody(body, phKeysByField[fk]) ||
                sectionHasExampleMarker(body)
              ) {
                msg.textContent =
                  (v + 1) +
                  "번 구역에 내용이 없습니다. 예시는 본문 영역 클릭 시 자동으로 지워집니다. 본인 내용을 입력해 주세요. (빈 줄·서식만이면 제출할 수 없습니다.)";
                msg.style.color = "#b91c1c";
                msg.hidden = false;
                return;
              }
            }
            if (!editPayload) {
              if (countPendingThumbs() < 1) {
                msg.textContent = "썸네일 이미지를 1개 이상 선택해 주세요.";
                msg.style.color = "#b91c1c";
                msg.hidden = false;
                return;
              }
            } else if (countRemainingThumbsOnSubmit() < 1) {
              msg.textContent = "썸네일은 1개 이상 남겨야 합니다.";
              msg.style.color = "#b91c1c";
              msg.hidden = false;
              return;
            }
            if (countRemainingThumbsOnSubmit() > maxThumbCount) {
              notifyThumbLimitPopup();
              msg.textContent = "썸네일은 최대 " + maxThumbCount + "개까지 등록할 수 있습니다.";
              msg.style.color = "#b91c1c";
              msg.hidden = false;
              return;
            }
            for (var tv = 0; tv < pendingThumbFiles.length; tv++) {
              if (pendingThumbFiles[tv].size > 5 * 1024 * 1024) {
                msg.textContent = "썸네일 " + (tv + 1) + "번째 파일은 5MB 이하여야 합니다.";
                msg.style.color = "#b91c1c";
                msg.hidden = false;
                return;
              }
            }
            var isEdit = editPayload && editPayload.id;
            var fd = new FormData();
            fd.append("title", document.getElementById("uctitle").value.trim());
            fd.append("situation", ex.situation);
            fd.append("taskGoal", ex.taskGoal);
            fd.append("actionTaken", ex.actionTaken);
            fd.append("resultOutcome", ex.resultOutcome);
            fd.append("tags", document.getElementById("uctags").value);
            for (var t = 0; t < pendingThumbFiles.length; t++) {
              fd.append("thumbnail", pendingThumbFiles[t]);
            }
            var keptAttachSubmit = 0;
            var attachCbsSubmit = document.querySelectorAll(".js-uc-remove-attach");
            for (var asi = 0; asi < attachCbsSubmit.length; asi++) {
              if (!attachCbsSubmit[asi].checked) keptAttachSubmit++;
            }
            var newAttachCount = filesIn && filesIn.files ? filesIn.files.length : 0;
            if (keptAttachSubmit + newAttachCount > maxAttachCount) {
              msg.textContent =
                "첨부 파일은 최대 " +
                maxAttachCount +
                "개입니다. 기존 첨부를 제거한 뒤 새 파일을 선택해 주세요.";
              msg.style.color = "#b91c1c";
              msg.hidden = false;
              return;
            }
            if (filesIn && filesIn.files) {
              for (var f = 0; f < filesIn.files.length; f++) {
                if (filesIn.files[f].size > 20 * 1024 * 1024) {
                  msg.textContent = "첨부 파일은 20MB 이하여야 합니다.";
                  msg.style.color = "#b91c1c";
                  msg.hidden = false;
                  return;
                }
                fd.append("attachments", filesIn.files[f]);
              }
            }
            if (isEdit) {
              var rmThumb = [];
              if (thumbGrid) {
                var removedTiles = thumbGrid.querySelectorAll(".use-case-thumb-tile[data-existing-rp].is-removed");
                for (var ti = 0; ti < removedTiles.length; ti++) {
                  try {
                    var trp = decodeURIComponent(removedTiles[ti].getAttribute("data-existing-rp") || "");
                    if (trp) rmThumb.push(trp);
                  } catch (e) {}
                }
              }
              if (rmThumb.length) {
                fd.append("removeThumbnailPaths", JSON.stringify(rmThumb));
              }
              var rm = [];
              var cbs = document.querySelectorAll(".js-uc-remove-attach");
              for (var ci = 0; ci < cbs.length; ci++) {
                if (cbs[ci].checked) {
                  try {
                    var rp = decodeURIComponent(cbs[ci].getAttribute("data-rp") || "");
                    if (rp) rm.push(rp);
                  } catch (e) {}
                }
              }
              if (rm.length) {
                fd.append("removeAttachmentPaths", JSON.stringify(rm));
              }
            }
            msg.hidden = true;
            submitBtn.disabled = true;
            var url = isEdit ? "/api/ai-use-case-submissions/" + encodeURIComponent(editPayload.id) : "/api/ai-use-case-submissions";
            var method = isEdit ? "PUT" : "POST";
            fetch(url, { method: method, body: fd, credentials: "same-origin" })
              .then(function (r) {
                return r.json().then(function (j) {
                  return { ok: r.ok, j: j, status: r.status };
                });
              })
              .then(function (o) {
                if (o.ok && o.j && o.j.ok) {
                  if (isEdit && o.j && o.j.id) {
                    window.location.href = "/ai-cases/submit/" + encodeURIComponent(o.j.id) + "?updated=1";
                  } else {
                    window.location.href = "/ai-cases?submitted=1";
                  }
                  return;
                }
                msg.textContent = (o.j && o.j.error) || "저장에 실패했습니다.";
                msg.style.color = "#b91c1c";
                msg.hidden = false;
              })
              .catch(function () {
                msg.textContent = "요청에 실패했습니다.";
                msg.style.color = "#b91c1c";
                msg.hidden = false;
              })
              .finally(function () {
                submitBtn.disabled = false;
              });
          });
        }
      })();
    </script>
  </body>
</html>
