/* Home dashboard behaviour. All selectors are db-* scoped. */

(function () {
  "use strict";

  function updateGreeting() {
    const el = document.getElementById("db-greeting");
    if (!el) return;

    const hour = new Date().getHours();
    if (hour < 5) el.textContent = "Late session";
    else if (hour < 12) el.textContent = "Good morning";
    else if (hour < 17) el.textContent = "Good afternoon";
    else if (hour < 21) el.textContent = "Good evening";
    else el.textContent = "Evening review";
  }

  function updateClock() {
    const el = document.getElementById("db-clock");
    if (!el) return;

    el.textContent = new Intl.DateTimeFormat(undefined, {
      hour: "2-digit",
      minute: "2-digit",
      second: "2-digit",
      hour12: false,
    }).format(new Date());
  }

  function getIsoWeek(date) {
    const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
    const dayNum = d.getUTCDay() || 7;
    d.setUTCDate(d.getUTCDate() + 4 - dayNum);
    const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
    return Math.ceil(((d - yearStart) / 86400000 + 1) / 7);
  }

  function updateStats() {
    const now = new Date();
    const year = now.getFullYear();
    const start = new Date(year, 0, 1);
    const nextYear = new Date(year + 1, 0, 1);
    const dayOfYear = Math.floor((now - start) / 86400000) + 1;
    const daysInYear = Math.round((nextYear - start) / 86400000);
    const daysLeft = Math.max(0, daysInYear - dayOfYear);
    const month = new Intl.DateTimeFormat(undefined, { month: "short" }).format(now);
    const pct = ((dayOfYear / daysInYear) * 100).toFixed(1);

    setText("db-stat-day", dayOfYear);
    setText("db-stat-week", "W" + getIsoWeek(now));
    setText("db-stat-month", month);
    setText("db-stat-left", daysLeft);
    setText("db-year-pct", pct + "%");

    const fill = document.getElementById("db-year-fill");
    if (fill) fill.style.width = pct + "%";
  }

  function setText(id, value) {
    const el = document.getElementById(id);
    if (el) el.textContent = value;
  }

  function escHtml(str) {
    return String(str)
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;");
  }

  function normaliseHref(href, prefix) {
    if (!href || href.startsWith("http") || href.startsWith("#")) return null;
    const base = (prefix || "").replace(/\/$/, "");
    if (!base || href.startsWith(base + "/")) return href;
    return href.startsWith("/") ? base + href : base + "/" + href;
  }

  function extractLinks(doc, max, prefix) {
    const items = [];
    const seen = new Set();
    const links = doc.querySelectorAll("#content li a[href], .org-ul li a[href], ul li a[href]");

    for (const a of links) {
      const href = normaliseHref(a.getAttribute("href"), prefix);
      const title = a.textContent.trim();
      if (!href || !title || seen.has(href)) continue;

      const li = a.closest("li");
      const dateMatch = li ? li.textContent.match(/\b\d{4}-\d{2}-\d{2}\b/) : null;
      seen.add(href);
      items.push({ href, title, date: dateMatch ? dateMatch[0] : null });
      if (items.length >= max) break;
    }

    return items;
  }

  function renderFeed(ulId, items) {
    const ul = document.getElementById(ulId);
    if (!ul || !items.length) return;

    ul.innerHTML = items
      .map(({ href, title, date }) => (
        `<li class="db-feed__item">` +
        `<span class="db-feed__dot"></span>` +
        `<a href="${escHtml(href)}">${escHtml(title)}</a>` +
        (date ? `<span class="db-feed__meta">${escHtml(date)}</span>` : "") +
        `</li>`
      ))
      .join("");
  }

  async function loadFeed(listUrl, ulId, max, prefix) {
    try {
      const resp = await fetch(listUrl, { credentials: "same-origin" });
      if (!resp.ok) return;

      const html = await resp.text();
      const doc = new DOMParser().parseFromString(html, "text/html");
      renderFeed(ulId, extractLinks(doc, max, prefix));
    } catch (_) {
      /* Fallback links remain in the HTML. */
    }
  }

  function initCommandFilter() {
    const input = document.getElementById("db-command-search");
    const nav = document.getElementById("db-quicknav");
    if (!input || !nav) return;

    const items = Array.from(nav.querySelectorAll(".db-qn-item"));
    const applyFilter = () => {
      const query = input.value.trim().toLowerCase();
      items.forEach((item) => {
        const haystack = [
          item.textContent,
          item.getAttribute("href"),
          item.dataset.keywords,
        ].join(" ").toLowerCase();
        item.classList.toggle("is-hidden", Boolean(query && !haystack.includes(query)));
      });
    };

    input.addEventListener("input", applyFilter);
    document.addEventListener("keydown", (event) => {
      if (event.key === "/" && !/^(input|textarea|select)$/i.test(event.target.tagName)) {
        event.preventDefault();
        input.focus();
      }
    });
  }

  function init() {
    updateGreeting();
    updateClock();
    updateStats();
    initCommandFilter();

    setInterval(updateClock, 1000);
    loadFeed("/blogs/blogs-list.html", "db-feed-blogs", 6, "/blogs");
    loadFeed("/posts/posts-list.html", "db-feed-posts", 6, "/posts");
    loadFeed("/recently-updated.html", "db-feed-recent", 6, "");
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    init();
  }
})();
