/**
 * React hooks wiring AdMob into the app.
 *
 *  useAdBanner()
 *    Mount on any page that should show a sticky banner at the bottom
 *    (Live TV + Movie / Series player screens). Automatically hides on
 *    unmount so navigation away from the player cleans the view.
 *
 *  useChannelSwitchInterstitial(count)
 *    Pass the running channel-switch counter; the hook fires an
 *    interstitial every N switches (N comes from the admin panel's
 *    `ads_interstitial_every` — fetched via /api/public/ad-config).
 */

import { useEffect, useRef, useCallback } from "react";
import {
  hideBanner,
  showBanner,
  prepareInterstitial,
  showInterstitialNow,
  getInterstitialEvery,
} from "@/lib/admob";
import { useEntitlement } from "@/hooks/useEntitlement";

function apiBase(): string {
  // Vite-first, with Capacitor / legacy fallbacks. IMPORTANT: do NOT
  // reference `process.env` in this bundle — `process` doesn't exist in
  // the browser and throws "process is not defined" at runtime, which
  // was crashing the LiveTV page as soon as useAdBanner mounted.
  // @ts-expect-error Vite inlines import.meta.env at build time
  return import.meta.env.VITE_BACKEND_URL
    // @ts-expect-error Vite inlines import.meta.env at build time
    || import.meta.env.REACT_APP_BACKEND_URL
    // @ts-expect-error — last-resort global injected by the native shell
    || (globalThis as any).REACT_APP_BACKEND_URL
    || "";
}

/**
 * Shows / hides the AdMob banner based on the current route. Mount
 * ONCE at the app root (inside <Router>) so the same banner instance
 * persists as the user navigates between Home / Live TV / Movies /
 * Series / Account, avoiding the show→hide→reshow flicker that
 * per-page mounts caused.
 *
 * FEATURE (2026-01) — global app-wide banner. Previously the banner
 * only showed on LiveTV + during active VOD playback. Now it shows
 * on EVERY content route, hidden only on auth / setup / admin / full-
 * screen-experience routes where it would clip the page chrome.
 *
 * Premium / ad-free users continue to never see ads (the underlying
 * `useEntitlement().adsEnabled` flag handles that).
 */
const BANNER_ROUTES: ReadonlyArray<string> = [
  "/",
  "/live-tv",
  "/movies",
  "/series",
  "/account",
];

export function useGlobalBanner(): void {
  const { adsEnabled } = useEntitlement();
  // useLocation() can throw outside a Router. Wrap so the hook is
  // safe to call even from a top-level App component that mounts
  // before the Router pushes its context. In practice we always
  // mount this hook inside <Router>, so the catch is defensive only.
  let pathname = "/";
  try {
    // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
    const { useLocation } = require("react-router-dom") as typeof import("react-router-dom");
    pathname = useLocation().pathname;
  } catch { /* no router yet */ }

  const wantsBanner = adsEnabled && BANNER_ROUTES.includes(pathname);

  useEffect(() => {
    if (!wantsBanner) {
      void hideBanner();
      return;
    }
    void showBanner(apiBase());
    // Eagerly prepare the next interstitial too — channel switches +
    // VOD opens benefit from a pre-loaded slot.
    void prepareInterstitial(apiBase());
    // Note: we deliberately do NOT hide on unmount of THIS hook —
    // the hook lives for the whole app lifetime, only the route
    // change re-runs the effect and may flip wantsBanner.
  }, [wantsBanner]);
}

export function useAdBanner(active = true): void {
  const { adsEnabled } = useEntitlement();
  useEffect(() => {
    // Premium users / expired trial users never see ads.
    if (!active || !adsEnabled) {
      void hideBanner();
      return;
    }
    void showBanner(apiBase());
    // Also eagerly prepare the next interstitial so channel-switch taps
    // don't have to wait for an async load when the threshold is reached.
    void prepareInterstitial(apiBase());
    return () => {
      void hideBanner();
    };
  }, [active, adsEnabled]);
}

/**
 * Fires an interstitial every N channel switches. `count` is the running
 * total of channel selections since the page was mounted. The hook
 * idempotently fires on the Nth, 2Nth, 3Nth switch, etc.
 *
 * BUG-4 FIX (2026-05): previously called the early-return
 * `showInterstitial()` which silently no-op'd when the slot wasn't
 * pre-loaded — so on the 2nd channel switch (the most common trigger)
 * the user saw nothing and ad inventory was wasted. Now uses
 * `showInterstitialNow()` which lazily kicks off `prepareInterstitial`
 * + waits up to `maxWaitMs` for the AdMob `onInterstitialAdLoaded`
 * event, AND we eagerly re-prime the next slot regardless of outcome
 * so back-to-back channel hops feel snappy.
 */
export function useChannelSwitchInterstitial(count: number): void {
  const { adsEnabled } = useEntitlement();
  const lastFired = useRef(0);
  const inFlight = useRef(false);
  useEffect(() => {
    if (!adsEnabled) return;
    const every = getInterstitialEvery();
    if (!every || count <= 0) return;
    if (count % every !== 0) return;
    if (count === lastFired.current) return;
    if (inFlight.current) return;
    lastFired.current = count;
    inFlight.current = true;
    (async () => {
      try {
        // 6-second wait — slightly longer than the default 4s in
        // showInterstitialNow because channel-switch latency tolerance
        // is higher than the global periodic timer.
        const shown = await showInterstitialNow({ maxWaitMs: 6000 });
        console.log(
          `[AdMob] channel-switch interstitial @ switch #${count} — ${shown ? "shown" : "fallback / no-fill"}`,
        );
      } finally {
        // Eagerly pre-load the next interstitial so the following
        // trigger fires instantly. onInterstitialAdDismissed inside
        // admob.ts already does this, but doing it here too is
        // harmless (AdMob de-dupes prepare calls).
        void prepareInterstitial(apiBase());
        inFlight.current = false;
      }
    })();
  }, [count, adsEnabled]);
}

/**
 * Exposes a stable `triggerInterstitial()` callback that pages can call
 * BEFORE starting playback (e.g. opening a movie/episode) and AFTER
 * exiting playback (closing the modal). Premium users / expired-trial
 * users get a no-op.
 *
 *   const fireAd = useTriggerInterstitial();
 *   onClick={() => { await fireAd(); setPlaying(movie); }}
 */
export function useTriggerInterstitial() {
  const { adsEnabled } = useEntitlement();
  return useCallback(async (): Promise<boolean> => {
    if (!adsEnabled) return false;
    return showInterstitialNow();
  }, [adsEnabled]);
}
