/**
 * Return YouTube Dislike — Nebula extension
 *
 * Uses the public Return YouTube Dislike API:
 *   https://returnyoutubedislikeapi.com/votes?videoId=...
 *
 * Inspired by / adapted from Anarios/return-youtube-dislike (GPL-3.0):
 *   https://github.com/Anarios/return-youtube-dislike
 * Attribution: https://returnyoutubedislike.com
 *
 * This is a simplified page-script port for Nebula's native extension
 * runtime (no chrome.* APIs, no vote submission, no premium features).
 */
(function () {
  "use strict";

  const API_BASE = "https://returnyoutubedislikeapi.com";
  const ATTR_LINK = "https://returnyoutubedislike.com";

  let currentVideoId = null;
  let inFlight = null;
  let lastApplied = null;
  let pollTimer = null;

  function numberFormat(value) {
    const n = Number(value) || 0;
    try {
      return new Intl.NumberFormat(document.documentElement.lang || navigator.language || "en", {
        notation: "compact",
        compactDisplay: "short",
      }).format(n);
    } catch (_) {
      return String(n);
    }
  }

  function getVideoId(url) {
    try {
      const u = new URL(url || location.href);
      if (u.pathname.startsWith("/shorts/")) {
        return u.pathname.split("/")[2] || null;
      }
      if (u.pathname.startsWith("/live/")) {
        return u.pathname.split("/")[2] || null;
      }
      if (u.pathname.startsWith("/embed/")) {
        return u.pathname.split("/")[2] || null;
      }
      if (u.pathname.startsWith("/clip")) {
        const meta =
          document.querySelector("meta[itemprop='videoId']") ||
          document.querySelector("meta[itemprop='identifier']");
        return meta ? meta.content : null;
      }
      return u.searchParams.get("v");
    } catch (_) {
      return null;
    }
  }

  function isWatchContext() {
    const path = location.pathname;
    return (
      path === "/watch" ||
      path.startsWith("/shorts/") ||
      path.startsWith("/live/") ||
      path.startsWith("/embed/") ||
      path.startsWith("/clip")
    );
  }

  function qs(root, selectors) {
    const list = Array.isArray(selectors) ? selectors : [selectors];
    for (const sel of list) {
      if (!sel) continue;
      const el = (root || document).querySelector(sel);
      if (el) return el;
    }
    return null;
  }

  function getButtonsRoot() {
    if (location.pathname.startsWith("/shorts/")) {
      const nodes = document.querySelectorAll(
        "reel-action-bar-view-model, #like-button > ytd-like-button-renderer, ytm-like-button-renderer"
      );
      for (const node of nodes) {
        const rect = node.getBoundingClientRect();
        if (rect.width > 0 && rect.height > 0) return node;
      }
      return nodes[0] || null;
    }

    // Try segmented first (new YouTube design)
    let el = qs(document, ["ytd-segmented-like-dislike-button-renderer"]);
    if (el) return el;

    // Fallback to old design
    el = qs(document, [
      "#top-level-buttons-computed",
      "ytd-menu-renderer.ytd-watch-metadata",
      ".slim-video-action-bar-actions",
    ]);
    return el || null;
  }

  function getLikeButton() {
    // New design (segmented)
    let btn = qs(document, ["#segmented-like-button"]);
    if (btn) return btn;

    // Fallback
    const root = getButtonsRoot();
    if (root) {
      btn = qs(root, [
        "like-button-view-model",
        "yt-spec-button-shape-next",
        "ytd-like-button-renderer",
        ":first-child",
      ]);
      if (btn) return btn;
    }

    return qs(document, ["like-button-view-model", "ytd-like-button-renderer"]) || null;
  }

  function getDislikeButton() {
    // New design (segmented)
    let btn = qs(document, ["#segmented-dislike-button"]);
    if (btn) return btn;

    // Fallback
    const root = getButtonsRoot();
    if (root) {
      btn = qs(root, [
        "dislike-button-view-model",
        "yt-spec-button-shape-next",
        "ytd-toggle-button-renderer",
        ":nth-child(2)",
      ]);
      if (btn) return btn;
    }

    return qs(document, ["dislike-button-view-model", "#dislike-button", "ytd-toggle-button-renderer"]) || null;
  }

  function getNativeButton(container) {
    return container ? qs(container, ["button", "tp-yt-paper-button#button"]) : null;
  }

  function getLikeCountFromButton() {
    try {
      const like = getLikeButton();
      const btn = getNativeButton(like) || like;
      const label = btn && (btn.getAttribute("aria-label") || btn.textContent || "");
      if (!label) return null;

      const text = String(label).trim();
      
      // Parse abbreviated numbers: "28M" → 28000000, "3K" → 3000, "82" → 82
      const match = text.match(/^([\d.]+)\s*([MKmk]?)(?:\s|$)/);
      if (!match) return null;

      let num = parseFloat(match[1]);
      if (!Number.isFinite(num)) return null;

      const suffix = (match[2] || "").toUpperCase();
      if (suffix === "M") num *= 1_000_000;
      else if (suffix === "K") num *= 1_000;

      return Math.round(num);
    } catch (_) {
      return null;
    }
  }

  function matchDislikeButtonWidth(dislikeButton) {
    if (!dislikeButton) return;
    try {
      const likeBtn = getLikeButton();
      if (!likeBtn) return;

      const likeWidth = window.getComputedStyle(likeBtn).width;
      if (!likeWidth || likeWidth === "auto") return;

      dislikeButton.style.setProperty("min-width", likeWidth, "important");
      dislikeButton.style.setProperty("flex-shrink", "0", "important");

      const native = getNativeButton(dislikeButton);
      if (native) {
        native.style.setProperty("min-width", likeWidth, "important");
        native.style.setProperty("flex-shrink", "0", "important");
      }
    } catch (_) {
      // Ignore — cosmetic only.
    }
  }

  function ensureDislikeLabel(dislikeButton) {
    matchDislikeButtonWidth(dislikeButton);

    let label = dislikeButton.querySelector(".ryd-dislike-count");
    if (label) return label;

    const native = getNativeButton(dislikeButton) || dislikeButton;
    label = document.createElement("span");
    label.className = "ryd-dislike-count";
    label.setAttribute("data-ryd", "1");
    label.title = "Dislikes via Return YouTube Dislike — " + ATTR_LINK;

    // Prefer injecting into the button so YouTube's layout keeps the text.
    const textHost =
      qs(native, [
        ".yt-spec-button-shape-next__button-text-content",
        ".ytSpecButtonShapeNextButtonTextContent",
      ]) || native;

    // Switch icon-only dislike buttons to icon+text style when possible.
    if (native && native.classList) {
      native.classList.remove("yt-spec-button-shape-next--icon-button");
      native.classList.add("yt-spec-button-shape-next--icon-leading");
    }

    textHost.appendChild(label);
    return label;
  }

  function setDislikeText(text) {
    const dislike = getDislikeButton();
    if (!dislike) return false;
    const label = ensureDislikeLabel(dislike);
    if (label.textContent !== text) {
      label.textContent = text;
    }
    return true;
  }

  function createOrUpdateBar(likes, dislikes) {
    if (location.pathname.startsWith("/shorts/")) return;

    const likeBtn = getLikeButton();
    const dislikeBtn = getDislikeButton();
    const actions = qs(document, [
      "#top-level-buttons-computed",
      "#actions-inner",
      "#actions",
      "#menu-container",
    ]);

    if (!likeBtn || !dislikeBtn || !actions) {
      console.log("[RYD] Bar creation: missing", {
        likeBtn: !!likeBtn,
        dislikeBtn: !!dislikeBtn,
        actions: !!actions,
      });
      return;
    }

    const total = likes + dislikes;
    const widthPercent = total > 0 ? (likes / total) * 100 : 50;
    const tooltip = `${likes.toLocaleString()} / ${dislikes.toLocaleString()} — ${widthPercent.toFixed(1)}% liked`;

    const likeRect = likeBtn.getBoundingClientRect();
    const dislikeRect = dislikeBtn.getBoundingClientRect();
    const actionsRect = actions.getBoundingClientRect();
    const pillLeft = Math.max(0, likeRect.left - actionsRect.left);
    const pillWidth = Math.max(0, dislikeRect.right - likeRect.left);
    const pillBottom = Math.max(likeRect.bottom, dislikeRect.bottom) - actionsRect.top;

    if (!pillWidth) return;

    let tooltipEl = actions.querySelector(".ryd-tooltip");
    if (!tooltipEl) {
      console.log("[RYD] Creating new bar under like/dislike buttons");

      // Create without innerHTML to avoid Trusted Types CSP
      tooltipEl = document.createElement("div");
      tooltipEl.className = "ryd-tooltip";

      const bar = document.createElement("div");
      bar.id = "ryd-bar";

      const barContainer = document.createElement("div");
      barContainer.id = "ryd-bar-container";
      barContainer.appendChild(bar);
      tooltipEl.appendChild(barContainer);

      tooltipEl.title = tooltip + " · " + ATTR_LINK;

      if (getComputedStyle(actions).position === "static") {
        actions.style.setProperty("position", "relative", "important");
      }
      actions.style.setProperty("overflow", "visible", "important");
      actions.style.setProperty("padding-bottom", "10px", "important");

      actions.appendChild(tooltipEl);
      console.log("[RYD] Bar created");
    }

    tooltipEl.style.left = pillLeft + "px";
    tooltipEl.style.top = pillBottom + 2 + "px";
    tooltipEl.style.width = pillWidth + "px";
    tooltipEl.title = tooltip + " · " + ATTR_LINK;
    const bar = tooltipEl.querySelector("#ryd-bar");
    if (bar) {
      bar.style.width = widthPercent + "%";
    }
  }

  async function fetchVotes(videoId) {
    const likeCount = getLikeCountFromButton();
    const url =
      API_BASE +
      "/votes?videoId=" +
      encodeURIComponent(videoId) +
      (likeCount != null ? "&likeCount=" + encodeURIComponent(String(likeCount)) : "");

    console.log("[RYD] Fetching:", url);

    const response = await fetch(url, {
      method: "GET",
      headers: { Accept: "application/json" },
      credentials: "omit",
    });

    if (response.status === 429) {
      throw new Error("rate-limited");
    }
    if (!response.ok) {
      throw new Error("http-" + response.status);
    }

    const data = await response.json();
    console.log("[RYD] Response:", data);
    
    if (!data || typeof data.dislikes !== "number") {
      throw new Error("bad-payload");
    }
    return data;
  }

  async function applyForVideo(videoId) {
    if (!videoId) {
      console.log("[RYD] No video ID");
      return;
    }
    if (inFlight === videoId) {
      console.log("[RYD] Already in-flight for", videoId);
      return;
    }
    if (lastApplied === videoId && document.querySelector(".ryd-dislike-count")) {
      console.log("[RYD] Already applied for", videoId);
      return;
    }

    console.log("[RYD] Applying for video:", videoId);
    inFlight = videoId;
    try {
      const data = await fetchVotes(videoId);
      if (getVideoId(location.href) !== videoId) {
        console.log("[RYD] Video changed during fetch");
        return;
      }

      const likes = getLikeCountFromButton() || Number(data.likes) || 0;
      const dislikes = Number(data.dislikes) || 0;

      console.log("[RYD] Likes:", likes, "Dislikes:", dislikes);

      // Retry UI injection briefly — YouTube hydrates buttons asynchronously.
      let tries = 0;
      const paint = () => {
        const dislikeBtn = getDislikeButton();
        console.log("[RYD] Paint attempt", tries, "- dislike button:", dislikeBtn ? "found" : "missing");
        
        const ok = setDislikeText(numberFormat(dislikes));
        if (ok) {
          console.log("[RYD] Successfully set dislike text");
          createOrUpdateBar(likes, dislikes);
          lastApplied = videoId;
          return;
        }
        if (++tries < 25) {
          window.setTimeout(paint, 200);
        } else {
          console.warn("[RYD] Failed to find dislike button after 25 tries");
        }
      };
      paint();
    } catch (err) {
      if (getVideoId(location.href) === videoId) {
        setDislikeText("—");
      }
      console.error("[RYD] Error:", err.message);
    } finally {
      if (inFlight === videoId) inFlight = null;
    }
  }

  function refresh() {
    if (!isWatchContext()) {
      currentVideoId = null;
      return;
    }
    const videoId = getVideoId(location.href);
    if (!videoId) return;
    if (videoId !== currentVideoId) {
      currentVideoId = videoId;
      lastApplied = null;
      applyForVideo(videoId);
    } else if (lastApplied !== videoId) {
      applyForVideo(videoId);
    } else {
      // Re-paint if YouTube rebuilt the button DOM.
      if (!document.querySelector(".ryd-dislike-count")) {
        lastApplied = null;
        applyForVideo(videoId);
      }
    }
  }

  function start() {
    refresh();

    document.addEventListener("yt-navigate-finish", refresh, true);
    window.addEventListener("yt-navigate-finish", refresh, true);
    window.addEventListener("popstate", refresh);

    // YouTube SPA fallback when custom events are missed.
    let lastHref = location.href;
    window.setInterval(() => {
      if (location.href !== lastHref) {
        lastHref = location.href;
        refresh();
        return;
      }
      if (isWatchContext() && currentVideoId && !document.querySelector(".ryd-dislike-count")) {
        lastApplied = null;
        refresh();
      }
    }, 1500);

    const observer = new MutationObserver(() => {
      if (isWatchContext() && currentVideoId && !document.querySelector(".ryd-dislike-count")) {
        lastApplied = null;
        refresh();
      }
    });
    observer.observe(document.documentElement, { childList: true, subtree: true });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", start, { once: true });
  } else {
    start();
  }
})();
