(function () {
  const wall = document.getElementById("notes-wall");
  const form = document.getElementById("notes-form");
  const authorInput = document.getElementById("note-author");
  const contentInput = document.getElementById("note-content");
  const authorFilter = document.getElementById("notes-author-filter");
  let notesCache = [];

  if (!wall) return;

  function escapeHtml(str) {
    return str
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;")
      .replace(/'/g, "&#039;");
  }

  function renderNote(note) {
    const el = document.createElement("div");
    el.className = "note";

    el.innerHTML = `
      <div class="note-meta">
        <span class="note-author">${escapeHtml(note.author_name)}</span>
        <time datetime="${note.created_at}">
          ${new Date(note.created_at).toLocaleString()}
        </time>
      </div>
      <div class="note-content">
        ${escapeHtml(note.content).replace(/\n/g, "<br>")}
      </div>
    `;

    return el;
  }

  function normaliseAuthor(author) {
    return (author || "").trim();
  }

  function populateAuthorFilter(notes) {
    if (!authorFilter) return;

    const previousValue = authorFilter.value;
    const authors = Array.from(
      new Set(notes.map(note => normaliseAuthor(note.author_name)).filter(Boolean))
    ).sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" }));

    authorFilter.innerHTML = '<option value="">All authors</option>';

    authors.forEach(author => {
      const option = document.createElement("option");
      option.value = author;
      option.textContent = author;
      authorFilter.appendChild(option);
    });

    authorFilter.value = authors.includes(previousValue) ? previousValue : "";
  }

  function renderNotes() {
    wall.innerHTML = "";

    const selectedAuthor = authorFilter ? authorFilter.value : "";
    const notes = selectedAuthor
      ? notesCache.filter(note => normaliseAuthor(note.author_name) === selectedAuthor)
      : notesCache;

    if (notesCache.length === 0) {
      wall.innerHTML = "<p>No notes yet.</p>";
      return;
    }

    if (notes.length === 0) {
      wall.innerHTML = "<p>No notes for this author.</p>";
      return;
    }

    notes.forEach(note => {
      wall.appendChild(renderNote(note));
    });
  }

  async function loadNotes() {
    wall.innerHTML = "<p>Loading notes…</p>";

    try {
      const res = await fetch("/api/notes");
      if (!res.ok) throw new Error("Failed to fetch notes");

      const notes = await res.json();
      notesCache = notes;
      populateAuthorFilter(notesCache);
      renderNotes();
    } catch (err) {
      console.error(err);
      wall.innerHTML = "<p>Could not load notes.</p>";
    }
  }

  async function submitNote(e) {
    e.preventDefault();

    const author = authorInput.value.trim();
    const content = contentInput.value.trim();

    if (!author || !content) return;

    form.querySelector("button").disabled = true;

    try {
      const res = await fetch("/api/notes", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          author_name: author,
          content: content,
        }),
      });

      if (!res.ok) {
        const err = await res.json();
        throw new Error(err.detail || "Failed to post note");
      }

      contentInput.value = "";
      await loadNotes();
    } catch (err) {
      alert(err.message);
    } finally {
      form.querySelector("button").disabled = false;
    }
  }

  if (form) {
    form.addEventListener("submit", submitNote);
  }

  if (authorFilter) {
    authorFilter.addEventListener("change", renderNotes);
  }

  loadNotes();
})();
