/**
 * Mounts the overlay Vue app inside a closed shadow root appended to
 * document.documentElement — the host page's CSS and CSP stay untouched.
 *
 * Styles strategy: Vite extracts everything imported by the content entry
 * (kit.css, phosphor icons, SFC styles) into assets/style.css. At runtime we
 * fetch it from the extension bundle, rewrite the kit's absolute /assets/ font
 * URLs to extension URLs, and adopt it as a constructable stylesheet — no
 * <style> injection into the page, so strict style-src pages stay happy.
 */
import { createApp, reactive } from "vue";
import browser from "webextension-polyfill";
import App from "./App.vue";
import "./overlay.css";
import "gnexus-ui-kit/dist/css/kit.css";
import "gnexus-ui-kit/dist/assets/fonts/phosphor-icons/src/css/icons.css";

export interface OverlayState {
  mode: "idle" | "picker";
  recording: boolean;
  /** transient message shown in the flash toast (replay results etc.) */
  flash: string | null;
}

export interface Overlay {
  startPicker: () => void;
  setRecorderState: (recording: boolean) => void;
  setFlash: (text: string | null) => void;
  destroy: () => void;
}

function rewriteKitAssetUrls(css: string): string {
  const base = browser.runtime.getURL("");
  return css
    .replaceAll("url(/assets/", `url(${base}assets/`)
    .replaceAll('url("/assets/', `url("${base}assets/`)
    .replaceAll("url('/assets/", `url('${base}assets/`);
}

// same palette as the panel (packages/web/src/theme.css); overlay components
// reference these via var(--color-*, fallback) — the fallbacks stay in sync
const OVERLAY_VARS = {
  "--color-bg": "#10121c",
  "--color-surface": "#1f2335",
  "--color-border": "#2f334d",
  "--color-text": "#c0caf5",
  "--color-text-dim": "#787c99",
  "--color-accent": "#7aa2f7",
  "--color-success": "#9ece6a",
  "--color-warning": "#e0af68",
  "--color-danger": "#f7768e",
};

export function mountOverlay(): Overlay {
  const host = document.createElement("div");
  host.id = "ltt-overlay-host";
  host.style.cssText = "all: initial; position: fixed; inset: 0; z-index: 2147483647; pointer-events: none;";
  document.documentElement.appendChild(host);

  const shadowRoot = host.attachShadow({ mode: "closed" });
  const mountPoint = document.createElement("div");
  const vars = Object.entries(OVERLAY_VARS)
    .map(([name, value]) => `${name}:${value};`)
    .join("");
  mountPoint.style.cssText = `all: initial; pointer-events: none; width: 100%; height: 100%; ${vars}`;
  shadowRoot.appendChild(mountPoint);

  const state = reactive<OverlayState>({ mode: "idle", recording: false, flash: null });
  const app = createApp(App, { state });
  app.mount(mountPoint);

  let flashTimer: number | null = null;

  // styles load asynchronously; the overlay works unstyled until then
  void (async () => {
    try {
      const url = browser.runtime.getURL("assets/style.css");
      const text = await (await fetch(url)).text();
      const sheet = new CSSStyleSheet();
      sheet.replaceSync(rewriteKitAssetUrls(text));
      shadowRoot.adoptedStyleSheets = [...shadowRoot.adoptedStyleSheets, sheet];
    } catch {
      // styles are cosmetic — the overlay must keep working without them
    }
  })();

  // constructable stylesheets ignore @font-face (Chromium limitation), so the
  // Phosphor font must be registered through the FontFace API instead
  void (async () => {
    try {
      const font = new FontFace(
        "Phosphor",
        `url(${browser.runtime.getURL("assets/fonts/phosphor-icons/src/fonts/Phosphor.woff2")})`,
        { weight: "400", style: "normal", display: "block" }
      );
      await font.load();
      document.fonts.add(font);
    } catch {
      // icons degrade to empty boxes; the overlay keeps working
    }
  })();

  return {
    startPicker: () => {
      state.mode = "picker";
      state.recording = false;
    },
    setRecorderState: (recording: boolean) => {
      // only toggles the bar; picking stays opt-in via the bar's Note button
      state.recording = recording;
      if (!recording && state.mode === "picker") state.mode = "idle";
    },
    setFlash: (text: string | null) => {
      state.flash = text;
      if (flashTimer) window.clearTimeout(flashTimer);
      if (text) flashTimer = window.setTimeout(() => (state.flash = null), 5000);
    },
    destroy: () => {
      app.unmount();
      host.remove();
    },
  };
}