"use strict";

(function bootSafeSceneContent() {
  var Common = globalThis.SafeSceneCommon;
  var SkipController = globalThis.SafeSceneSkipController.SkipController;
  var controllerByVideo = new Map();
  var state = {
    pageContext: null,
    resolution: null,
    status: "booting",
    lastAction: null,
    skippedScenes: [],
    debug: {
      videoCount: 0,
      controllerVideoCount: 0,
      videoContexts: [],
      lastResolveDurationMs: 0
    },
    updatedAt: null
  };
  var settings = Common.clone(Common.DEFAULT_SETTINGS);
  var providerStatus = {
    skipitConnected: false
  };
  var updateInfo = {
    hasUpdate: false
  };
  var overlayNode = null;
  var overlayTimer = null;
  var noticeNode = null;
  var noticeTimer = null;
  var lastNoticeKey = null;
  var lastWarningOverlayKey = null;
  var lastUpdateNoticeVersion = null;
  var resolveTimer = null;
  var resolveSequence = 0;
  var resolveInFlight = false;
  var queuedResolve = false;
  var discoveryIntervalId = null;

  function sanitizeDisplayText(value) {
    return String(value || "").replace(/\bnudity\b/gi, "explicit scenes");
  }

  function getSceneSources() {
    if (!state.resolution || !state.resolution.sceneMatch || !Array.isArray(state.resolution.sceneMatch.sources)) {
      return [];
    }

    return state.resolution.sceneMatch.sources;
  }

  function hasSkipitSource() {
    return getSceneSources().some(function hasSource(source) {
      return String(source && source.kind || "").indexOf("skipit-") === 0 || String(source && source.name || "") === "Skipit";
    });
  }

  function hasCountedSceneSource() {
    return getSceneSources().some(function hasCount(source) {
      return Number(source && source.sceneCount || 0) > 0;
    });
  }

  function getSceneSourceNames() {
    var names = getSceneSources()
      .map(function mapName(source) {
        return source && source.name ? source.name : "";
      })
      .filter(Boolean);

    return names.length ? names.join(", ") : "external review sources";
  }

  function sendMessage(message) {
    return chrome.runtime.sendMessage(message);
  }

  function showOverlay(message) {
    if (!overlayNode) {
      overlayNode = document.createElement("div");
      overlayNode.setAttribute("data-safescene-owned", "true");
      overlayNode.style.position = "fixed";
      overlayNode.style.right = "18px";
      overlayNode.style.bottom = "18px";
      overlayNode.style.zIndex = "2147483647";
      overlayNode.style.background = "rgba(7, 16, 29, 0.92)";
      overlayNode.style.color = "#f8fafc";
      overlayNode.style.border = "1px solid rgba(96, 165, 250, 0.28)";
      overlayNode.style.backdropFilter = "blur(16px)";
      overlayNode.style.fontFamily = "\"Avenir Next\", \"Segoe UI\", sans-serif";
      overlayNode.style.fontSize = "13px";
      overlayNode.style.lineHeight = "1.4";
      overlayNode.style.padding = "10px 12px";
      overlayNode.style.borderRadius = "12px";
      overlayNode.style.boxShadow = "0 10px 30px rgba(0, 0, 0, 0.25)";
      overlayNode.style.maxWidth = "320px";
      document.documentElement.appendChild(overlayNode);
    }

    overlayNode.textContent = message;
    overlayNode.style.display = "block";

    if (overlayTimer) {
      clearTimeout(overlayTimer);
    }

    overlayTimer = setTimeout(function hideOverlay() {
      if (overlayNode) {
        overlayNode.style.display = "none";
      }
    }, 2400);
  }

  function ensureNoticeNode() {
    if (noticeNode) {
      return noticeNode;
    }

    noticeNode = document.createElement("div");
    noticeNode.setAttribute("data-safescene-owned", "true");
    noticeNode.style.position = "fixed";
    noticeNode.style.top = "18px";
    noticeNode.style.right = "18px";
    noticeNode.style.zIndex = "2147483647";
    noticeNode.style.width = "min(360px, calc(100vw - 24px))";
    noticeNode.style.background = "rgba(8, 13, 22, 0.96)";
    noticeNode.style.border = "1px solid rgba(56, 189, 248, 0.24)";
    noticeNode.style.borderRadius = "18px";
    noticeNode.style.boxShadow = "0 22px 60px rgba(0, 0, 0, 0.45)";
    noticeNode.style.backdropFilter = "blur(18px)";
    noticeNode.style.padding = "14px 14px 12px";
    noticeNode.style.color = "#f8fafc";
    noticeNode.style.fontFamily = "\"Avenir Next\", \"Segoe UI\", sans-serif";
    noticeNode.style.display = "none";
    document.documentElement.appendChild(noticeNode);
    return noticeNode;
  }

  function showNotice(payload) {
    var container = ensureNoticeNode();
    var buttonHtml = payload.buttonLabel
      ? "<button data-action=\"primary\" style=\"border:1px solid rgba(56,189,248,0.18);background:linear-gradient(135deg,#2563eb,#0ea5e9);color:#eff6ff;border-radius:999px;padding:8px 12px;font:600 12px/1.2 inherit;cursor:pointer;box-shadow:0 10px 24px rgba(14,165,233,0.2);\">" + payload.buttonLabel + "</button>"
      : "";

    container.innerHTML = "" +
      "<div style=\"display:flex;align-items:flex-start;justify-content:space-between;gap:10px;\">" +
        "<div>" +
          "<div style=\"font-size:11px;letter-spacing:0.12em;text-transform:uppercase;font-weight:700;color:#38bdf8;\">ta3meya</div>" +
          "<div style=\"margin-top:4px;font-size:16px;line-height:1.2;font-weight:700;\">" + payload.title + "</div>" +
        "</div>" +
        "<button data-action=\"dismiss\" style=\"border:0;background:transparent;color:#94a3b8;font-size:18px;line-height:1;cursor:pointer;\">&times;</button>" +
      "</div>" +
      "<p style=\"margin:10px 0 0;color:#d7e3f3;font-size:13px;line-height:1.45;\">" + payload.body + "</p>" +
      "<div style=\"margin-top:12px;display:flex;align-items:center;justify-content:space-between;gap:10px;\">" +
        "<div style=\"font-size:11px;color:#94a3b8;\">" + payload.footnote + "</div>" +
        buttonHtml +
      "</div>";

    container.style.display = "block";

    container.onclick = function onNoticeClick(event) {
      var action = event.target && event.target.getAttribute ? event.target.getAttribute("data-action") : "";

      if (action === "dismiss") {
        container.style.display = "none";
        return;
      }

      if (action === "primary" && payload.onPrimaryAction) {
        payload.onPrimaryAction();
      }
    };

    if (noticeTimer) {
      clearTimeout(noticeTimer);
    }

    noticeTimer = setTimeout(function hideNotice() {
      if (noticeNode) {
        noticeNode.style.display = "none";
      }
    }, 9000);
  }

  function isSafeSceneOwnedNode(node) {
    if (!node) {
      return false;
    }

    if (node.nodeType === Node.TEXT_NODE) {
      return isSafeSceneOwnedNode(node.parentElement || node.parentNode || null);
    }

    if (node.nodeType !== Node.ELEMENT_NODE) {
      return false;
    }

    if (node.getAttribute && node.getAttribute("data-safescene-owned") === "true") {
      return true;
    }

    return Boolean(node.closest && node.closest("[data-safescene-owned=\"true\"]"));
  }

  function getFirstMetaContent(selector) {
    var node = document.querySelector(selector);
    return node && node.content ? node.content.trim() : "";
  }

  function getHeadingText() {
    var nodes = Array.from(document.querySelectorAll("h1, h2"))
      .map(function mapHeading(node) {
        return String(node.textContent || "").replace(/\s+/g, " ").trim();
      })
      .filter(Boolean);

    return nodes[0] || "";
  }

  function tryGetIframeDocument(iframeNode) {
    try {
      if (!iframeNode || !iframeNode.contentDocument) {
        return null;
      }

      return iframeNode.contentDocument;
    } catch (error) {
      return null;
    }
  }

  function discoverVideos() {
    var visitedRoots = new Set();
    var videos = new Map();
    var contextCounts = {
      main: 0,
      shadow: 0,
      iframe: 0
    };

    function registerVideo(videoNode, context) {
      if (!videoNode || videos.has(videoNode)) {
        return;
      }

      videos.set(videoNode, context);
      contextCounts[context] += 1;
    }

    function walkRoot(rootNode, context) {
      if (!rootNode || visitedRoots.has(rootNode) || typeof rootNode.querySelectorAll !== "function") {
        return;
      }

      visitedRoots.add(rootNode);

      Array.from(rootNode.querySelectorAll("video")).forEach(function addVideo(videoNode) {
        registerVideo(videoNode, context);
      });

      Array.from(rootNode.querySelectorAll("*")).forEach(function inspectNode(node) {
        if (node.shadowRoot) {
          walkRoot(node.shadowRoot, "shadow");
        }

        if (node.tagName === "IFRAME") {
          var iframeDocument = tryGetIframeDocument(node);
          if (iframeDocument) {
            walkRoot(iframeDocument, "iframe");
          }
        }
      });
    }

    walkRoot(document, "main");

    return {
      videos: Array.from(videos.keys()),
      videoContexts: Object.keys(contextCounts).filter(function filterContext(key) {
        return contextCounts[key] > 0;
      }),
      total: videos.size
    };
  }

  function buildPageContext() {
    var videoDiscovery = discoverVideos();
    return {
      url: location.href,
      hostname: location.hostname,
      pathname: location.pathname,
      title: document.title || "",
      ogTitle: getFirstMetaContent('meta[property="og:title"]'),
      twitterTitle: getFirstMetaContent('meta[name="twitter:title"]'),
      heading: getHeadingText(),
      hasVideo: videoDiscovery.total > 0,
      videoCount: videoDiscovery.total,
      videoContexts: videoDiscovery.videoContexts
    };
  }

  function emitStateUpdate() {
    state.updatedAt = new Date().toISOString();
    document.documentElement.setAttribute("data-safescene-status", state.status || "unknown");
    sendMessage({
      type: "stateUpdated",
      pageContext: state.pageContext,
      resolution: state.resolution,
      state: state
    }).catch(function ignoreErrors() {
      return null;
    });
  }

  function getExactRanges() {
    if (!state.resolution || !state.resolution.sceneMatch) {
      return [];
    }
    return Array.isArray(state.resolution.sceneMatch.exactRanges)
      ? state.resolution.sceneMatch.exactRanges
      : [];
  }

  function getPlannedSceneCount() {
    if (!state.resolution || !state.resolution.sceneMatch) {
      return 0;
    }

    if (Array.isArray(state.resolution.sceneMatch.exactRanges) && state.resolution.sceneMatch.exactRanges.length) {
      return state.resolution.sceneMatch.exactRanges.length;
    }

    return Number(state.resolution.sceneMatch.matchingSceneCount || 0);
  }

  function attachController(video) {
    if (controllerByVideo.has(video)) {
      return;
    }

    var controller = new SkipController(video, {
      settings: settings,
      ranges: getExactRanges(),
      onNotify: function onNotify(event) {
        showOverlay("Skipping explicit scene in " + event.secondsUntil + "s");
      },
      onSkip: function onSkip(event) {
        state.skippedScenes.push({
          id: event.range.id,
          category: event.range.category,
          sourceName: event.range.sourceName || "unknown",
          start: event.range.startSeconds,
          end: event.range.endSeconds,
          at: new Date().toISOString()
        });
        state.lastAction = {
          type: "skip",
          at: new Date().toISOString(),
          rangeId: event.range.id,
          seekTarget: event.seekTarget
        };
        emitStateUpdate();
        showOverlay(
          "Skipped explicit scene " +
          Common.formatSeconds(event.range.startSeconds) +
          "-" +
          Common.formatSeconds(event.range.endSeconds)
        );
      }
    });

    controllerByVideo.set(video, controller);
  }

  function refreshControllers() {
    var videoDiscovery = discoverVideos();
    state.debug.videoCount = videoDiscovery.total;
    state.debug.controllerVideoCount = controllerByVideo.size;
    state.debug.videoContexts = videoDiscovery.videoContexts.slice();

    videoDiscovery.videos.forEach(attachController);
    controllerByVideo.forEach(function updateController(controller, video) {
      if (!video.isConnected) {
        controller.destroy();
        controllerByVideo.delete(video);
        return;
      }

      controller.setSettings(settings);
      controller.setRanges(getExactRanges());
      controller.tick();
    });

    state.debug.controllerVideoCount = controllerByVideo.size;
    return videoDiscovery.total;
  }

  async function resolveNow() {
    if (resolveInFlight) {
      queuedResolve = true;
      return;
    }

    resolveInFlight = true;
    var resolveId = resolveSequence + 1;
    resolveSequence = resolveId;
    state.pageContext = buildPageContext();
    if (!state.resolution) {
      state.status = "resolving";
    }
    emitStateUpdate();
    var resolveStartedAt = Date.now();

    try {
      var response = await sendMessage({
        type: "resolveEpisode",
        pageContext: state.pageContext
      });

      if (resolveId !== resolveSequence) {
        return;
      }

      settings = Object.assign({}, settings, response.settings || {});
      providerStatus = Object.assign({}, providerStatus, response.providerStatus || {});
      updateInfo = Object.assign({}, updateInfo, response.updateInfo || {});
      state.resolution = response.resolution || null;
      state.status = response.resolution ? response.resolution.status : "idle";
      state.debug.lastResolveDurationMs = Date.now() - resolveStartedAt;
      refreshControllers();

      if (response.resolution && response.resolution.status === "warning_only") {
        maybeShowWarningOverlay();
      }

      maybeShowUpdateNotice();
      maybeShowImmediateNotice();
    } catch (error) {
      if (resolveId !== resolveSequence) {
        return;
      }

      state.status = "error";
      state.debug.lastResolveDurationMs = Date.now() - resolveStartedAt;
      state.lastAction = {
        type: "error",
        at: new Date().toISOString(),
        message: error && error.message ? error.message : String(error)
      };
    } finally {
      if (resolveId === resolveSequence) {
        emitStateUpdate();
      }

      resolveInFlight = false;
      if (queuedResolve) {
        queuedResolve = false;
        scheduleResolve();
      }
    }
  }

  function maybeShowWarningOverlay() {
    if (!state.resolution || state.resolution.status !== "warning_only") {
      return;
    }

    var detected = state.resolution.detected || null;
    var warningKey = detected
      ? [
        detected.showTitle,
        detected.seasonNumber,
        detected.episodeNumber,
        "warning_only"
      ].join("|")
      : [
        state.pageContext && state.pageContext.hostname || "",
        state.pageContext && state.pageContext.pathname || "",
        "warning_only"
      ].join("|");

    if (lastWarningOverlayKey === warningKey) {
      return;
    }

    lastWarningOverlayKey = warningKey;
    showOverlay(sanitizeDisplayText("Episode detected, but only warning-level scene data exists."));
  }

  function maybeShowImmediateNotice() {
    if (!state.resolution || !state.resolution.detected || !state.resolution.sceneMatch) {
      return;
    }

    var matchingSceneCount = getPlannedSceneCount();
    if (!matchingSceneCount) {
      return;
    }

    var noticeKey = [
      state.resolution.detected.showTitle,
      state.resolution.detected.seasonNumber,
      state.resolution.detected.episodeNumber,
      matchingSceneCount,
      state.resolution.sceneMatch.status,
      providerStatus.skipitConnected ? "connected" : "guest"
    ].join("|");

    if (lastNoticeKey === noticeKey) {
      return;
    }

    lastNoticeKey = noticeKey;

    if (state.resolution.sceneMatch.status === "exact") {
      showNotice({
        title: "Auto-skip is active",
        body: "This episode has " + matchingSceneCount + " explicit scene(s) matching your filters. They will be skipped automatically.",
        footnote: "You can disable skipping from the ta3meya popup."
      });
      return;
    }

    if (hasSkipitSource() && providerStatus.skipitConnected) {
      showNotice({
        title: "Scene data found",
        body: "This episode has " + matchingSceneCount + " explicit scene(s) matching your filters, but exact skip ranges are not available yet for this episode.",
        footnote: "ta3meya will keep warning until exact ranges are published."
      });
      return;
    }

    if (hasSkipitSource()) {
      showNotice({
        title: "Scene data found",
        body: "This episode has " + matchingSceneCount + " explicit scene(s) matching your filters. Connect Skipit to load exact auto-skip ranges for this episode.",
        footnote: "Without connected provider access, ta3meya can only warn.",
        buttonLabel: "Connect Skipit",
        onPrimaryAction: function onPrimaryAction() {
          sendMessage({ type: "openSkipitConnect" }).catch(function ignore() {
            window.open("https://getskipit.com/extension-auth", "_blank");
          });
        }
      });
      return;
    }

    showNotice({
      title: "Warning-only source found",
      body: hasCountedSceneSource()
        ? "This episode has warning-level explicit scene data from " + getSceneSourceNames() + ", but exact auto-skip ranges are not available from those sources."
        : "This episode is flagged for explicit scenes by " + getSceneSourceNames() + ", but only warning-level review data is available.",
      footnote: "ta3meya can warn from fallback review sources even when no auto-skip ranges exist."
    });
  }

  function maybeShowUpdateNotice() {
    if (!updateInfo || !updateInfo.hasUpdate) {
      return;
    }

    var noticeVersion = String(updateInfo.latestVersion || "");
    if (lastUpdateNoticeVersion === noticeVersion) {
      return;
    }

    lastUpdateNoticeVersion = noticeVersion;

    showNotice({
      title: "Update available",
      body: "There's an update. Please go to the website.",
      footnote: noticeVersion
        ? "Latest version: " + noticeVersion
        : "A newer ta3meya build is available.",
      buttonLabel: "Open website",
      onPrimaryAction: function onPrimaryAction() {
        sendMessage({ type: "openUpdateWebsite" }).catch(function ignore() {
          window.open(updateInfo.websiteUrl || "https://ta3meya.bals.pro", "_blank");
        });
      }
    });
  }

  function scheduleResolve() {
    if (resolveTimer) {
      clearTimeout(resolveTimer);
    }
    resolveTimer = setTimeout(resolveNow, 350);
  }

  function installMutationObservers() {
    var titleNode = document.querySelector("title");
    if (titleNode) {
      var titleObserver = new MutationObserver(scheduleResolve);
      titleObserver.observe(titleNode, {
        subtree: true,
        childList: true,
        characterData: true
      });
    }

    var bodyObserver = new MutationObserver(function onBodyMutate(mutations) {
      var shouldResolve = Array.from(mutations || []).some(function hasRelevantMutation(mutation) {
        var addedNodes = Array.from(mutation.addedNodes || []);
        var removedNodes = Array.from(mutation.removedNodes || []);
        return addedNodes.concat(removedNodes).some(function isRelevant(node) {
          return !isSafeSceneOwnedNode(node);
        });
      });

      refreshControllers();
      if (shouldResolve) {
        scheduleResolve();
      }
    });
    bodyObserver.observe(document.documentElement, {
      subtree: true,
      childList: true
    });
  }

  function installHistoryHooks() {
    var originalPushState = history.pushState;
    var originalReplaceState = history.replaceState;

    history.pushState = function patchedPushState() {
      var result = originalPushState.apply(history, arguments);
      scheduleResolve();
      return result;
    };

    history.replaceState = function patchedReplaceState() {
      var result = originalReplaceState.apply(history, arguments);
      scheduleResolve();
      return result;
    };

    window.addEventListener("popstate", scheduleResolve);
  }

  function installDiscoveryPolling() {
    if (discoveryIntervalId) {
      clearInterval(discoveryIntervalId);
    }

    discoveryIntervalId = setInterval(function pollForVideoChanges() {
      var discoveredVideoCount = refreshControllers();

      if (!state.pageContext) {
        return;
      }

      if (discoveredVideoCount !== Number(state.pageContext.videoCount || 0)) {
        scheduleResolve();
      }
    }, 2000);
  }

  chrome.runtime.onMessage.addListener(function onMessage(message, sender, sendResponse) {
    if (message.type === "getState") {
      sendResponse({
        pageContext: state.pageContext,
        resolution: state.resolution,
        state: state,
        providerStatus: providerStatus,
        updateInfo: updateInfo
      });
      return;
    }

    if (message.type === "settingsChanged") {
      settings = Object.assign({}, settings, message.settings || {});
      refreshControllers();
      sendResponse({ ok: true });
      return;
    }

    if (message.type === "refreshDetection") {
      scheduleResolve();
      sendResponse({ ok: true });
      return;
    }
  });

  (async function init() {
    try {
      var response = await sendMessage({ type: "getSettings" });
      settings = Object.assign({}, settings, response.settings || {});
      providerStatus = Object.assign({}, providerStatus, response.providerStatus || {});
      updateInfo = Object.assign({}, updateInfo, response.updateInfo || {});
    } catch (error) {
      // Keep defaults.
    }

    refreshControllers();
    installMutationObservers();
    installHistoryHooks();
    installDiscoveryPolling();
    maybeShowUpdateNotice();
    resolveNow();
  }());
}());
