// AdBlockMaxxer — Spotify Web Player ad handler (ISOLATED world, open.spotify.com).
//
// HONEST NOTE: Spotify audio ads are streamed from the same CDN as your music and the
// app actively fights tampering, so there is no clean "block the ad URL" move on the web
// player. The reliable, non-breaking thing we CAN do is detect an ad and mute + fast-skip
// it, then restore your audio the moment your music returns. Your music is never left muted.
//
// The stronger Spotify fix is on the listening device itself (especially your iPhone) via
// a blocking DNS / AdGuard — see MOBILE-iOS.md. This script just cleans up the web player.
//
// Honours the "spotifyMute" toggle from the popup.

(function () {
  "use strict";

  let enabled = true;
  let allowed = true; // not allowlisted
  let snoozeUntil = 0;
  let perf = false;
  const KEY = "spotifyMute";
  const HOST = location.hostname;

  function refreshAllow(list) {
    const h = location.hostname;
    allowed = !((list || []).some(function (d) { return h === d || h.endsWith("." + d); }));
  }
  function active() { return enabled && allowed && Date.now() >= snoozeUntil; }
  chrome.storage.local.get([KEY, "allowlist", "snoozeUntil", "perfMode"], function (r) {
    if (r && r[KEY] === false) enabled = false;
    snoozeUntil = (r && r.snoozeUntil) || 0;
    if (r && r.perfMode) perf = true;
    refreshAllow(r && r.allowlist);
    startLoop();
  });
  chrome.storage.onChanged.addListener(function (c) {
    if (c[KEY]) enabled = c[KEY].newValue !== false;
    if (c.snoozeUntil) snoozeUntil = c.snoozeUntil.newValue || 0;
    if (c.allowlist) refreshAllow(c.allowlist.newValue);
    if (c.perfMode) { perf = !!c.perfMode.newValue; startLoop(); }
  });

  let weMuted = false;
  let lastBump = 0;
  function bump() {
    const now = Date.now();
    if (now - lastBump < 8000) return;
    lastBump = now;
    try { chrome.runtime.sendMessage({ type: "kill", n: 1, category: "spotify", host: HOST }); } catch (e) {}
  }

  function isAd() {
    // Spotify flips the tab title to "Advertisement" during audio ads.
    if (document.title.trim().toLowerCase() === "advertisement") return true;
    // DOM signals (selectors drift over time — multiple fallbacks).
    if (document.querySelector('[data-testid="track-info-advertiser"]')) return true;
    const ariaAd = document.querySelector('[aria-label="Advertisement"], [aria-label="advertisement"]');
    if (ariaAd) return true;
    // Now-playing link pointing at an ad context.
    const link = document.querySelector('a[data-testid="context-item-link"], a[data-testid="nowplaying-track-link"]');
    if (link && /\/ad[s]?(\/|$|\?)/i.test(link.getAttribute("href") || "")) return true;
    return false;
  }

  function media() {
    return document.querySelector("audio, video");
  }

  function tick() {
    if (!active()) {
      if (weMuted) { const m = media(); if (m) m.muted = false; weMuted = false; }
      return;
    }
    const m = media();
    if (!m) return;

    if (isAd()) {
      if (!m.muted) { m.muted = true; weMuted = true; }
      // Try to fast-forward the ad; MSE may reject the seek, which is fine — it stays muted.
      if (isFinite(m.duration) && m.duration > 0) {
        try { m.currentTime = m.duration; } catch (e) {}
      }
      bump();
    } else if (weMuted) {
      // Music is back — give the user their audio.
      m.muted = false;
      weMuted = false;
    }

    // Dismiss the "Get Premium" / upsell interstitial if it appears.
    const close = document.querySelector('button[data-testid="ad-overlay-close-button"], button[aria-label="Close"]');
    if (isAd() && close) close.click();
  }

  let loopIv = null;
  function startLoop() {
    if (loopIv) clearInterval(loopIv);
    loopIv = setInterval(tick, perf ? 1200 : 500);
  }
  startLoop();
})();
