(async () => {
  // Helper to get dynamic context
  const getContext = () => {
    const idLink = document.querySelector("a.id-link");
    if (!idLink) return null;
    return {
      postid: +idLink.innerText,
      poster: document.querySelector("a#a_username")?.innerText,
      tags: [...document.querySelectorAll("#tags > .badge")].map(t => t.innerText.slice(0, -2))
    };
  };

  const queryapi = async (url, data, method = 'GET') => {
    let req;
    if (method == 'POST') {
      req = await fetch(url, {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(data)
      });
    }
    else {
      let s = [];
      for (const [key, val] of Object.entries(data))
        s.push(encodeURIComponent(key) + "=" + encodeURIComponent(val));
      req = await fetch(url + '?' + s.join('&'));
    }
    return await req.json();
  };

  const get = async (url, data) => queryapi(url, data, 'GET');
  const post = async (url, data) => queryapi(url, data, 'POST');

  const renderTags = _tags => {
    [...document.querySelectorAll("#tags > .badge")].forEach(tag => tag.parentElement.removeChild(tag));
    _tags.reverse().forEach(tag => {
      const a = document.createElement("a");
      a.href = `/tag/${tag.normalized}`;
      a.style = "color: inherit !important";
      a.innerHTML = tag.tag;
      // Admin specific: edit event
      // Note: delegation handles this now if we set it up, OR we can attach here since elements are new.
      // But delegation is cleaner if possible. However, editTagEvent relies on 'e.target'.

      const span = document.createElement("span");
      span.classList.add("badge", "mr-2");
      span.setAttribute('tooltip', tag.user);

      tag.badge.split(" ").forEach(b => span.classList.add(b));

      const delbutton = document.createElement("a");
      delbutton.innerHTML = " &#215;";
      delbutton.href = "#";
      // Class for delegation
      delbutton.classList.add("admin-deltag");

      span.insertAdjacentElement("beforeend", a);
      span.innerHTML += '&nbsp;';
      span.insertAdjacentElement("beforeend", delbutton);

      document.querySelector("#tags").insertAdjacentElement("afterbegin", span);
    });
  };

  const deleteEvent = async e => {
    e.preventDefault();
    const ctx = getContext();
    if (!ctx) return;
    const { postid } = ctx;

    if (!confirm("Do you really want to delete this tag?"))
      return;
    const tagname = e.target.parentElement.querySelector('a:first-child').innerText;

    const res = await (await fetch("/api/v2/admin/" + postid + "/tags/" + encodeURIComponent(tagname), {
      method: 'DELETE'
    })).json();

    if (!res.success)
      return alert("uff");

    renderTags(res.tags);
  };

  const addtagClick = (e) => {
    if (e) e.preventDefault();
    const ctx = getContext();
    if (!ctx) return;
    const { postid, tags } = ctx;

    const insert = document.querySelector("a#a_addtag");
    if (insert.previousElementSibling && insert.previousElementSibling.querySelector('input')) {
      insert.previousElementSibling.querySelector('input').focus();
      return;
    }

    const span = document.createElement("span");
    span.classList.add("badge", "badge-light", "mr-2");

    const input = document.createElement("input");
    input.size = "10";
    input.value = "";
    input.setAttribute("list", "testlist");
    input.setAttribute("autoComplete", "off");

    span.insertAdjacentElement("afterbegin", input);
    insert.insertAdjacentElement("beforebegin", span);

    input.focus();

    let tt = null;
    let lastInput = '';
    const testList = document.querySelector('#testlist');

    input.addEventListener("keyup", async e => {
      if (e.key === "Enter") {
        const tmptag = input.value?.trim();
        // We should re-check tags from DOM? Or trust captured tags?
        // Captured 'tags' is safe for immediate check.
        if (tags.includes(tmptag))
          return alert("tag already exists");

        const res = await post("/api/v2/admin/" + postid + "/tags", {
          tagname: tmptag
        });
        if (!res.success) {
          alert(res.msg);
          return false;
        }
        renderTags(res.tags);
        if (span.parentElement) span.parentElement.removeChild(span);
        testList.innerText = "";
        addtagClick();
      }
      else if (e.key === "Escape") {
        if (span.parentElement) span.parentElement.removeChild(span);
        testList.innerText = "";
      }
      else {
        if (tt != null) clearTimeout(tt);
        tt = setTimeout(async () => {
          tt = null;
          const tmptag = input.value?.trim();
          if (tmptag == lastInput || tmptag.length <= 1) return false;
          testList.innerText = "";
          lastInput = tmptag;
          const res = await get('/api/v2/admin/tags/suggest', { q: tmptag });
          for (const entry of res.suggestions) {
            const option = document.createElement('option');
            option.value = entry.tag;
            if (!/fox/.test(navigator.userAgent))
              option.innerText = `tagged ${entry.tagged} times (score: ${entry.score.toFixed(2)})`;
            testList.insertAdjacentElement('beforeEnd', option);
          };
        }, 500);
      }
      return true;
    });

    input.addEventListener("focusout", ie => {
      if (input.value.length === 0)
        input.parentElement.parentElement.removeChild(input.parentElement);
    });
  };

  const toggleEvent = async (e) => {
    if (e) e.preventDefault();
    const ctx = getContext();
    if (!ctx) return;
    const { postid } = ctx;

    const res = await (await fetch('/api/v2/admin/' + encodeURIComponent(postid) + '/tags/toggle', {
      method: 'PUT'
    })).json();

    renderTags(res.tags);
  };

  const deleteButtonEvent = async e => {
    if (e) e.preventDefault();
    const ctx = getContext();
    if (!ctx) return;
    const { postid, poster } = ctx;

    const modal = document.getElementById('delete-item-modal');
    const idEl = document.getElementById('delete-item-id');
    const posterEl = document.getElementById('delete-item-poster');
    const confirmBtn = document.getElementById('delete-item-confirm');
    const cancelBtn = document.getElementById('delete-item-cancel');

    if (modal) {
      idEl.textContent = postid;
      posterEl.textContent = poster || 'unknown';
      modal.style.display = 'flex';

      const closeModal = () => {
        modal.style.display = 'none';
        confirmBtn.onclick = null;
        cancelBtn.onclick = null;
      };

      cancelBtn.onclick = closeModal;

      confirmBtn.onclick = async () => {
        confirmBtn.textContent = 'Deleting...';
        confirmBtn.disabled = true;
        const res = await post("/api/v2/admin/deletepost", {
          postid: postid
        });
        if (!res.success) {
          alert(res.msg);
          confirmBtn.textContent = 'Delete';
          confirmBtn.disabled = false;
        } else {
          closeModal();
          window.location.href = '/';
        }
      };
    }
  };

  const toggleFavEvent = async (e) => {
    const ctx = getContext();
    if (!ctx) return;
    const { postid } = ctx;

    const res = await post('/api/v2/admin/togglefav', {
      postid: postid
    });
    if (res.success) {
      const fav = document.querySelector("svg#a_favo > use").href;
      fav.baseVal = '/s/img/iconset.svg#heart_' + (fav.baseVal.match(/heart_(regular|solid)$/)[1] == "solid" ? "regular" : "solid");

      const favcontainer = document.querySelector('span#favs');
      favcontainer.innerHTML = "";
      favcontainer.hidden = !(favcontainer.hidden || res.favs.length > 0);
      res.favs.forEach(f => {
        const a = document.createElement('a');
        a.href = `/user/${f.user}/favs`;
        a.setAttribute('tooltip', f.user);
        a.setAttribute('flow', 'up');
        const img = document.createElement('img');
        img.src = `/t/${f.avatar}.webp`;
        img.style.height = "32px";
        img.style.width = "32px";
        a.insertAdjacentElement('beforeend', img);
        favcontainer.insertAdjacentElement('beforeend', a);
        favcontainer.innerHTML += "&nbsp;";
      });
    }
  };

  let tmptt = null;
  const editTagEvent = async e => {
    e.preventDefault();
    if (e.detail === 2) { // Double click
      clearTimeout(tmptt);
      const old = e.target;
      const parent = e.target.parentElement;
      const oldtag = e.target.innerText;

      const textfield = document.createElement('input');
      textfield.value = e.target.innerText;
      textfield.size = 10;

      parent.insertAdjacentElement('afterbegin', textfield);
      textfield.focus();
      parent.removeChild(e.target);
      // Hide delete button while editing
      const delBtn = parent.querySelector('a:last-child');
      if (delBtn) delBtn.style.display = 'none';

      textfield.addEventListener("keyup", async e => {
        if (e.key === 'Enter') {
          parent.removeChild(textfield);
          let res = await fetch('/api/v2/admin/tags/' + encodeURIComponent(oldtag), {
            method: 'PUT',
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ newtag: textfield.value })
          });
          const status = res.status;
          res = await res.json();
          switch (status) {
            case 200:
            case 201:
              parent.insertAdjacentElement('afterbegin', old);
              if (delBtn) delBtn.style.display = '';
              old.href = `/tag/${res.tag}`;
              old.innerText = res.tag.trim();
              break;
            default:
              console.log(res);
              break;
          }
        }
        else if (e.key === 'Escape') {
          parent.removeChild(textfield);
          parent.insertAdjacentElement('afterbegin', old);
          if (delBtn) delBtn.style.display = '';
        }
      });
    }
    else
      tmptt = setTimeout(() => location.href = e.target.href, 250);
    return false;
  };

  // Event Delegation
  document.addEventListener("click", e => {
    if (e.target.matches("a#a_addtag")) {
      addtagClick(e);
    } else if (e.target.matches("a#a_toggle")) {
      toggleEvent(e);
    } else if (e.target.closest("svg#a_favo")) {
      toggleFavEvent(e);
    } else if (e.target.closest("svg#a_delete")) {
      deleteButtonEvent(e);
    } else if (e.target.matches("#tags > .badge > a:first-child")) {
      editTagEvent(e);
    } else if (e.target.innerText === " \u00d7" && e.target.closest(".badge")) { // check text " x" or similar for delete?
      // Original was " &#215;" which is × (\u00d7). 
      // Logic in deleteEvent expects match. 
      // Let's rely on class or structure. 
      // In renderTags I added class 'admin-deltag'.
      // Existing tags in HTML might NOT have this class unless rendered by JS?
      // But existing tags are just HTML. We should match structure.
      // selector: "#tags > .badge > a:last-child"
      if (e.target.matches("#tags > .badge > a:last-child")) {
        deleteEvent(e);
      }
    }
  });

  document.addEventListener("keyup", e => {
    if (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA") return;
    const ctx = getContext();
    if (!ctx) return;

    if (e.key === "p") toggleEvent();
    else if (e.key === "i") addtagClick();
    else if (e.key === "x") deleteButtonEvent();
    else if (e.key === "f") toggleFavEvent();
  });

  // Settings page
  if (document.location.pathname === '/settings') {
    const saveAvatar = async e => {
      e.preventDefault();
      const avatar = +document.querySelector('input[name="i_avatar"]').value;
      let res = await fetch('/api/v2/settings/setAvatar', {
        method: 'PUT',
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ avatar })
      });
      const code = res.status;
      res = await res.json();
      if (code === 200) {
        document.querySelector('#img_avatar').src = `/t/${avatar}.webp`;
        document.querySelector('img.avatar').src = `/t/${avatar}.webp`;
      }
    };
    const sAvatar = document.querySelector('input#s_avatar');
    if (sAvatar) sAvatar.addEventListener('click', saveAvatar);
    const iAvatar = document.querySelector('input[name="i_avatar"]');
    if (iAvatar) iAvatar.addEventListener('keyup', async e => { if (e.key === 'Enter') await saveAvatar(e); });
  }
})();
