<section>
  <h1><%= post ? 'Edit Post' : 'New Post' %></h1>
  <form method="POST" action="<%= post ? '/admin/posts/' + post.id + '?_method=PUT' : '/admin/posts' %>">
    <label>
      Title
      <input type="text" name="title" value="<%= post ? post.title : '' %>" required>
    </label>
    <label>
      Slug
      <input type="text" name="slug" value="<%= post ? post.slug : '' %>" required>
    </label>
    <label>
      Excerpt
      <input type="text" name="excerpt" value="<%= post && post.excerpt ? post.excerpt : '' %>">
    </label>
    <label>
      Featured image
      <%- include('./_upload-field', { key: 'featuredImage', value: post && post.featuredImage ? post.featuredImage : '' }) %>
    </label>
    <div class="field-block">
      <span class="field-block-label">Body</span>
      <div class="editor-mode-tabs">
        <button type="button" class="editor-mode-tab is-active" data-mode="visual">Visual</button>
        <button type="button" class="editor-mode-tab" data-mode="html">HTML</button>
        <button type="button" id="insert-table-btn" class="editor-insert-table-btn">+ Insert table</button>
      </div>
      <p class="hint">Tables render correctly in Visual mode, but can only be edited as markup. Use "Insert table" or the HTML tab to add or change rows/columns.</p>
      <div id="editor-body" class="rich-editor"><%- post ? post.body : '' %></div>
      <!-- Raw-HTML view of the same field, toggled with the tabs above (see
           the script below). Hidden by default -- only one of this and
           #editor-body is ever visible at a time, but both stay in sync with
           #input-body (the actual value that gets submitted) regardless of
           which one the admin last edited. -->
      <textarea id="editor-body-html" class="rich-editor-html-source" hidden spellcheck="false"></textarea>
      <textarea name="body" id="input-body" hidden></textarea>
    </div>
    <label>
      Categories
      <span class="checkbox-group">
        <% categories.forEach(function(cat) { %>
          <label class="checkbox-inline">
            <input type="checkbox" name="categoryIds" value="<%= cat.id %>"
              <%= selectedCategoryIds.includes(cat.id) ? 'checked' : '' %>>
            <%= cat.name %>
          </label>
        <% }) %>
        <% if (!categories.length) { %><span class="hint">No categories yet. Add some under Admin &rarr; Categories.</span><% } %>
      </span>
    </label>
    <label>
      Status
      <select name="status">
        <option value="draft" <%= post && post.status === 'draft' ? 'selected' : '' %>>Draft</option>
        <option value="published" <%= post && post.status === 'published' ? 'selected' : '' %>>Published</option>
      </select>
    </label>
    <label>
      Published date <span class="hint">(leave blank to keep the existing date, or to auto-set on first publish)</span>
      <input type="datetime-local" name="publishedAt"
        value="<%= post && post.publishedAt ? post.publishedAt.toISOString().slice(0,16) : '' %>">
    </label>
    <button type="submit">Save</button>
  </form>
</section>

<script src="/js/media-picker.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/quill/1.3.7/quill.min.js"></script>
<script>
  (function () {
    var container = document.getElementById('editor-body');
    var hidden = document.getElementById('input-body');

    // --- Table support ---
    // Quill 1.x has no native <table> blot. Without this, any table (pasted
    // from Word/Excel/Sheets, or typed in the HTML tab and switched back to
    // Visual) gets its <table>/<tr>/<td> tags silently stripped by Quill's
    // default HTML parsing, leaving just the cell text run together with no
    // separators -- e.g. "PlanCostStorage" instead of a real table. This
    // registers the whole table as one opaque block embed that stores its
    // markup untouched, so it survives editing/saving/reloading intact. It
    // isn't cell-editable inside Visual mode (there's no cursor to click
    // into) -- that's what the HTML tab and "Insert table" button are for.
    var BlockEmbed = Quill.import('blots/block/embed');
    var Delta = Quill.import('delta');
    class TableEmbedBlot extends BlockEmbed {
      static create(value) {
        var node = super.create();
        node.className = 'cms-table-wrap';
        node.innerHTML = '<table>' + value + '</table>';
        return node;
      }
      static value(node) {
        var table = node.querySelector('table');
        return table ? table.innerHTML : '';
      }
    }
    TableEmbedBlot.blotName = 'tableEmbed';
    TableEmbedBlot.tagName = 'div';
    Quill.register(TableEmbedBlot);

    var quill = new Quill(container, {
      theme: 'snow',
      modules: {
        toolbar: {
          container: [['bold', 'italic', 'underline'], [{ header: [2, 3, false] }], [{ list: 'ordered' }, { list: 'bullet' }], ['blockquote', 'link', 'image'], ['clean']],
          // Quill's default image button embeds the picked file straight into
          // the post body as a giant base64 data: URI. A single photo easily
          // balloons past the server's request-size limit, so saving the post
          // silently failed (and looked like the editor was ignoring image
          // edits entirely). Uploading the file and inserting its URL instead
          // keeps the saved body tiny, the same way featured/gallery images
          // already work everywhere else in the admin.
          handlers: {
            image: function () {
              var range = this.quill.getSelection(true);
              var input = document.createElement('input');
              input.setAttribute('type', 'file');
              input.setAttribute('accept', 'image/*');
              input.click();
              input.onchange = function () {
                var file = input.files[0];
                if (!file) return;
                var formData = new FormData();
                formData.append('file', file);
                quill.insertText(range.index, 'Uploading image…', 'italic', true);
                fetch('/admin/uploads/image', { method: 'POST', body: formData })
                  .then(function (res) { return res.json(); })
                  .then(function (data) {
                    quill.deleteText(range.index, 'Uploading image…'.length);
                    if (data.url) {
                      quill.insertEmbed(range.index, 'image', data.url, 'user');
                      quill.setSelection(range.index + 1);
                    } else {
                      alert(data.error || 'Upload failed.');
                    }
                  })
                  .catch(function () {
                    quill.deleteText(range.index, 'Uploading image…'.length);
                    alert('Upload failed. Please try again.');
                  });
              };
            },
          },
        },
      },
    });
    // Intercepts <table> elements during paste and during the HTML-tab's
    // clipboard.convert() call below, replacing Quill's default behaviour
    // (recursing into rows/cells and flattening them into plain text) with a
    // single TableEmbedBlot holding the table's untouched inner markup.
    quill.clipboard.addMatcher('table', function (node) {
      return new Delta().insert({ tableEmbed: node.innerHTML });
    });

    hidden.value = quill.root.innerHTML;
    quill.on('text-change', function () { if (editorMode === 'visual') hidden.value = quill.root.innerHTML; });

    // --- Visual / HTML mode toggle ---
    // Quill auto-builds its toolbar as a sibling immediately before the
    // container it's attached to (since the toolbar option here is a config
    // array, not a selector) -- grab that reference now that it exists.
    var toolbarEl = container.previousElementSibling;
    var htmlSource = document.getElementById('editor-body-html');
    var modeTabs = document.querySelectorAll('.editor-mode-tab');
    var editorMode = 'visual';

    // Typing directly in the HTML box should also keep #input-body current,
    // so Save always submits whatever is on screen, in either mode, without
    // requiring a switch back to Visual first.
    htmlSource.addEventListener('input', function () {
      if (editorMode === 'html') hidden.value = htmlSource.value;
    });

    function setEditorMode(mode) {
      if (mode === editorMode) return;
      if (mode === 'html') {
        // Leaving Visual: hand the editor's current HTML to the source view.
        htmlSource.value = quill.root.innerHTML;
        container.hidden = true;
        if (toolbarEl) toolbarEl.hidden = true;
        htmlSource.hidden = false;
        htmlSource.focus();
      } else {
        // Leaving HTML: run whatever was typed through Quill's own
        // HTML-to-Delta conversion (the same parser it uses on paste), so
        // the visual editor shows a normalized version of it rather than
        // failing on markup Quill doesn't understand.
        quill.setContents(quill.clipboard.convert(htmlSource.value));
        hidden.value = quill.root.innerHTML;
        htmlSource.hidden = true;
        container.hidden = false;
        if (toolbarEl) toolbarEl.hidden = false;
      }
      editorMode = mode;
      modeTabs.forEach(function (t) { t.classList.toggle('is-active', t.getAttribute('data-mode') === mode); });
    }

    modeTabs.forEach(function (t) {
      t.addEventListener('click', function () { setEditorMode(t.getAttribute('data-mode')); });
    });

    // "Insert table": always drops the admin into the HTML tab with a
    // starter table at the cursor, since that's the only place table
    // structure can actually be edited (see the hint text above the
    // editor). Filling in real rows/columns is then just editing markup.
    var TABLE_TEMPLATE = '<table>\n  <thead>\n    <tr><th>Column 1</th><th>Column 2</th></tr>\n  </thead>\n  <tbody>\n    <tr><td>Row 1</td><td>Row 1</td></tr>\n    <tr><td>Row 2</td><td>Row 2</td></tr>\n  </tbody>\n</table>\n';
    document.getElementById('insert-table-btn').addEventListener('click', function () {
      if (editorMode === 'visual') setEditorMode('html');
      var start = htmlSource.selectionStart != null ? htmlSource.selectionStart : htmlSource.value.length;
      var end = htmlSource.selectionEnd != null ? htmlSource.selectionEnd : htmlSource.value.length;
      htmlSource.value = htmlSource.value.slice(0, start) + TABLE_TEMPLATE + htmlSource.value.slice(end);
      hidden.value = htmlSource.value;
      htmlSource.focus();
      var newPos = start + TABLE_TEMPLATE.length;
      htmlSource.setSelectionRange(newPos, newPos);
    });

    function setupUploadField(key) {
      var fileInput = document.getElementById('file-' + key);
      var hiddenInput = document.getElementById('input-' + key);
      var preview = document.getElementById('preview-' + key);
      var removeBtn = document.querySelector('.upload-remove[data-target="' + key + '"]');
      var browseBtn = document.querySelector('.upload-browse[data-target="' + key + '"]');
      if (!fileInput || !hiddenInput || !preview) return;

      function refresh() {
        if (hiddenInput.value) {
          preview.innerHTML = '<img src="' + hiddenInput.value + '" alt="">';
          if (removeBtn) removeBtn.hidden = false;
        } else {
          preview.innerHTML = '<span class="upload-empty">No image yet</span>';
          if (removeBtn) removeBtn.hidden = true;
        }
      }

      fileInput.addEventListener('change', function () {
        if (!fileInput.files.length) return;
        var formData = new FormData();
        formData.append('file', fileInput.files[0]);
        preview.innerHTML = '<span class="upload-empty">Uploading&hellip;</span>';
        fetch('/admin/uploads/image', { method: 'POST', body: formData })
          .then(function (res) { return res.json(); })
          .then(function (data) { if (data.url) { hiddenInput.value = data.url; } else { alert(data.error || 'Upload failed.'); } refresh(); })
          .catch(function () { alert('Upload failed. Please try again.'); refresh(); })
          .finally(function () { fileInput.value = ''; });
      });

      if (browseBtn) {
        browseBtn.addEventListener('click', function () {
          window.openMediaPicker({
            uploadUrl: '/admin/uploads/image',
            onSelect: function (url) { hiddenInput.value = url; refresh(); },
          });
        });
      }

      if (removeBtn) removeBtn.addEventListener('click', function () { hiddenInput.value = ''; refresh(); });
      refresh();
    }
    ['featuredImage'].forEach(setupUploadField);
  })();
</script>
