import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { BrowserRouter, HashRouter, Navigate, Route, Routes, useLocation } from "react-router-dom";

// On Tizen TV (WGT) and webOS the app is loaded via the `file://` protocol.
// HTML5 History (BrowserRouter) navigations like `navigate("/connect")`
// resolve to `file:////connect`, which the WebView reports as
// `net::ERR_FILE_NOT_FOUND`. HashRouter sidesteps that entirely by keeping
// the route in the URL fragment (`index.html#/connect`).
//
// Web preview (https://) and Capacitor Android (https://localhost) keep
// using BrowserRouter so deep links and back-button history stay clean.
const isFileProtocol =
  typeof window !== "undefined" && window.location && window.location.protocol === "file:";
const Router = isFileProtocol ? HashRouter : BrowserRouter;
import { Toaster as Sonner } from "@/components/ui/sonner";
import { Toaster } from "@/components/ui/toaster";
import { TooltipProvider } from "@/components/ui/tooltip";
import { useEffect, useState, type ReactNode } from "react";
import SplashScreen from "@/components/SplashScreen";
import { AuthProvider, useAuth } from "@/hooks/useAuth";
import { useSubscriberProfileSync } from "@/hooks/useSubscriberProfileSync";
import { useSharedProfilesSync } from "@/hooks/useSharedProfilesSync";
import { usePushNotifications } from "@/hooks/usePushNotifications";
import { usePlaybackMode } from "@/hooks/usePlaybackMode";
import { useExitInterstitial } from "@/hooks/useExitInterstitial";
import { useGlobalBanner } from "@/hooks/useAdMob";
import { cleanupOldResumes } from "@/hooks/useResumePlayback";
import { FocusProvider } from "@/components/focusable";
import Welcome from "./pages/Welcome.tsx";
import Login from "./pages/Login.tsx";
import Admin from "./pages/Admin.tsx";
import AdminBroadcast from "./pages/AdminBroadcast.tsx";
import ConnectProfile from "./pages/ConnectProfile.tsx";
import SelectProfile from "./pages/SelectProfile.tsx";
import Index from "./pages/Index.tsx";
import LiveTV from "./pages/LiveTV.tsx";
import Movies from "./pages/Movies.tsx";
import SeriesPage from "./pages/SeriesPage.tsx";
import WorldCup from "./pages/WorldCup.tsx";
import Account from "./pages/Account.tsx";
import DeviceActivation from "./pages/DeviceActivation.tsx";
import PairPortal from "./pages/PairPortal.tsx";
import Subscription from "./pages/Subscription.tsx";
import TrialExpired from "./pages/TrialExpired.tsx";
import NotFound from "./pages/NotFound.tsx";
import Privacy from "./pages/Privacy.tsx";
import BottomNav from "@/components/BottomNav";
import BottomLeftBar from "@/components/BottomLeftBar";
import BottomRightBar from "@/components/BottomRightBar";
import PeriodicInterstitial from "@/components/PeriodicInterstitial";
import BackButtonHandler from "@/components/BackButtonHandler";
import TVBackButton from "@/components/TVBackButton";
import { registerTizenRemoteKeys } from "@/native/tizenRemote";
import { useFocusWatchdog } from "@/hooks/useFocusWatchdog";
import UpdatePopup from "@/components/UpdatePopup";
import TVBanner from "@/components/TVBanner";
import FirstRunLanguageSelect, { hasChosenLanguage } from "@/components/FirstRunLanguageSelect";
import TVGuestLockOverlay from "@/components/TVGuestLockOverlay";
import TVTrialBadge from "@/components/TVTrialBadge";
import { EntitlementProvider, useEntitlement } from "@/hooks/useEntitlement";
import { isMobileNative } from "@/lib/platform";

const queryClient = new QueryClient();

// Clean up old resume playback entries on app boot
cleanupOldResumes();

const SPLASH_SESSION_KEY = "nadiplay_splash_shown";

// Gate the "home" pages: visitor must either be guest OR logged-in user.
const RequireEntry = ({ children }: { children: ReactNode }) => {
  const { user, isGuest, loading } = useAuth();
  const location = useLocation();
  if (loading) return null;
  if (!user && !isGuest) {
    return <Navigate to="/welcome" replace state={{ from: location.pathname }} />;
  }
  // Admins should land on /admin, not the regular home — unless they explicitly visit one.
  if (user?.role === "admin" && location.pathname === "/") {
    return <Navigate to="/admin" replace />;
  }
  return <>{children}</>;
};

// Renewal prompt: only LOGGED-IN users whose subscription has expired
// (days_remaining === 0) get bounced to /trial-expired so they can renew.
// Guests are NEVER gated — the app is free forever for them (with ads).
// Admins always bypass.
const RENEWAL_ALLOWED_PATHS = new Set([
  "/trial-expired",
  "/welcome",
  "/login",
  "/privacy",
  "/activate",
  "/pair",
  "/subscription",
  "/account",
]);
const RequireEntitlement = ({ children }: { children: ReactNode }) => {
  const { user } = useAuth();
  const { showRenewalPrompt, trialLoading } = useEntitlement();
  const location = useLocation();
  if (trialLoading) return null;
  if (user?.role === "admin") return <>{children}</>;
  if (showRenewalPrompt && !RENEWAL_ALLOWED_PATHS.has(location.pathname)) {
    return <Navigate to="/trial-expired" replace />;
  }
  return <>{children}</>;
};

const RequireAdmin = ({ children }: { children: ReactNode }) => {
  const { user, loading } = useAuth();
  if (loading) return null;
  if (!user) return <Navigate to="/login" replace />;
  if (user.role !== "admin") return <Navigate to="/" replace />;
  return <>{children}</>;
};

const AppRoutes = () => {
  const { user } = useAuth();
  useSubscriberProfileSync(user ? { id: user.id, role: user.role, xtream_mode: user.xtream_mode } : null);
  // Auto-mirror admin-configured shared profiles into the local store
  // as soon as the auth token is verified → no more "No profiles yet".
  useSharedProfilesSync(user ? { id: user.id, role: user.role, xtream_mode: user.xtream_mode } : null);
  // Register the device with FCM and listen for notification taps so
  // we can deep-link to the route the admin set (e.g. "/live-tv").
  // DEFERRED by 3s after login to prevent race condition crash.
  usePushNotifications(user ? { id: user.id, role: user.role } : null);
  usePlaybackMode();
  // Iter-6 (2026-01): show a full-screen interstitial every 3rd time
  // the user exits the native player (Live TV or VOD) — gated by
  // useEntitlement(), so premium and ad-free-unlocked users never see
  // it. The counter persists across cold starts in localStorage.
  useExitInterstitial({ everyN: 3 });
  // FEATURE (2026-01) — Global app-wide banner. Mounts ONCE here so
  // the AdMob banner persists across Home / Live TV / Movies / Series
  // / Account without the show→hide→reshow flicker the per-page
  // mounts used to cause. Hidden on auth / admin / setup routes by
  // the BANNER_ROUTES allow-list inside the hook. Always respects
  // useEntitlement().adsEnabled so premium / ad-free users see
  // nothing.
  useGlobalBanner();
  return (
    <Routes>
    <Route path="/welcome" element={<Welcome />} />
    <Route path="/login" element={<Login />} />
    <Route path="/connect" element={<ConnectProfile />} />
    <Route
      path="/select-profile"
      element={
        <RequireEntry>
          <SelectProfile />
        </RequireEntry>
      }
    />

    <Route
      path="/admin"
      element={
        <RequireAdmin>
          <Admin />
        </RequireAdmin>
      }
    />
    <Route
      path="/admin/broadcast"
      element={
        <RequireAdmin>
          <AdminBroadcast />
        </RequireAdmin>
      }
    />

    <Route
      path="/"
      element={
        <RequireEntry>
          <RequireEntitlement>
            <Index />
          </RequireEntitlement>
        </RequireEntry>
      }
    />
    <Route
      path="/live-tv"
      element={
        <RequireEntry>
          <RequireEntitlement>
            <LiveTV />
          </RequireEntitlement>
        </RequireEntry>
      }
    />
    <Route
      path="/movies"
      element={
        <RequireEntry>
          <RequireEntitlement>
            <Movies />
          </RequireEntitlement>
        </RequireEntry>
      }
    />
    <Route
      path="/series"
      element={
        <RequireEntry>
          <RequireEntitlement>
            <SeriesPage />
          </RequireEntitlement>
        </RequireEntry>
      }
    />
    <Route
      path="/world-cup"
      element={
        <RequireEntry>
          <RequireEntitlement>
            <WorldCup />
          </RequireEntitlement>
        </RequireEntry>
      }
    />
    <Route
      path="/account"
      element={
        <RequireEntry>
          <Account />
        </RequireEntry>
      }
    />
    <Route path="/activate" element={<DeviceActivation />} />
    <Route path="/pair" element={<PairPortal />} />
    <Route path="/subscription" element={<Subscription />} />
    <Route path="/trial-expired" element={<TrialExpired />} />
    <Route path="/privacy" element={<Privacy />} />
    <Route path="*" element={<NotFound />} />
    </Routes>
  );
};

const App = () => {
  const currentPath =
    typeof window !== "undefined" && window.location
      ? window.location.pathname
      : "/";
  const skipFirstRunLanguageOverlay =
    currentPath === "/login" ||
    currentPath.startsWith("/admin") ||
    currentPath === "/subscription";

  const [showSplash, setShowSplash] = useState<boolean>(() => {
    if (typeof window === "undefined") return false;
    const shouldUseSplash = isFileProtocol || isMobileNative();
    if (!shouldUseSplash) return false;
    try {
      return sessionStorage.getItem(SPLASH_SESSION_KEY) !== "1";
    } catch {
      return true;
    }
  });
  // First-run language picker shown only on the very first launch.
  // Persisted in localStorage so subsequent launches skip it directly.
  const [showLangPicker, setShowLangPicker] = useState<boolean>(() => {
    if (typeof window === "undefined") return false;
    // First-run language carousel is only for packaged TV/mobile app builds.
    // In web preview it blocks auth automation and adds unnecessary friction.
    const shouldUseFirstRunFlow = isFileProtocol || isMobileNative();
    return shouldUseFirstRunFlow && !hasChosenLanguage();
  });

  // Samsung Tizen TV — register the BACK key + media + colour buttons
  // with `tizen.tvinputdevice.registerKey()`. Without this call the
  // OS swallows keyCode 10009 (BACK) on every 2018+ TV and the app
  // force-closes instead of letting React Router pop the history.
  // Safe no-op on every other platform (the function bails out when
  // `window.tizen.tvinputdevice` is undefined).
  useEffect(() => {
    registerTizenRemoteKeys();
  }, []);

  // Samsung QA v1.4.2 — global focus watchdog. If a focused DOM node
  // disappears (modal closed, button disabled, route swapped) and
  // nobody else picks up focus, this hook detects the orphaned state
  // and re-anchors focus on a known-good target (tv-back-button →
  // login-submit → welcome cards). Prevents the "remote freezes"
  // failure mode that got 1.4.1 rejected.
  useFocusWatchdog();

  return (
    <QueryClientProvider client={queryClient}>
      <TooltipProvider>
        <FocusProvider>
          <AuthProvider>
            <EntitlementProvider>
            {showSplash && <SplashScreen onFinish={() => setShowSplash(false)} />}
            {!showSplash && showLangPicker && !skipFirstRunLanguageOverlay && (
              <FirstRunLanguageSelect onFinish={() => setShowLangPicker(false)} />
            )}
            <Toaster />
            <Sonner />
            <Router>
              <BackButtonHandler />
              {/* On-screen BACK arrow shown only on Samsung Tizen /
                  LG webOS — gives users an obvious escape hatch even
                  if they can't find the remote BACK button. Hidden on
                  Android / web and on root pages. */}
              <TVBackButton />
              <AppRoutes />
              {/* BottomNav has been retired in v1.3.1 — navigation now
                  lives in the header hamburger menu (HeaderMenu).
                  We keep the import only for legacy references and
                  intentionally do NOT mount it here. */}
              {false && <BottomNav />}
              {/* Dynamic info bars — clock+flag (left), location+weather (right).
                  FEATURE (2026-01) — Platform-specific visibility:
                  HIDDEN on Android / iOS native APKs (screen space is
                  precious on phones). VISIBLE on Smart-TV builds
                  (Tizen, WebOS) and web preview where the 16:9 estate
                  is plentiful. The split footer also leaves the
                  center free for the AdMob banner (now anchored
                  BOTTOM_CENTER — see lib/admob.ts). */}
              {!showSplash && !showLangPicker && !isMobileNative() && <BottomLeftBar />}
              {!showSplash && !showLangPicker && !isMobileNative() && <BottomRightBar />}
              {/* Periodic AdMob fullscreen ad (skippable). Only fires
                  when the user is past the splash + first-run picker. */}
              {!showSplash && !showLangPicker && <PeriodicInterstitial />}
              {/* Update popup waits until the splash + first-run language
                  picker finish, so the user always sees the app branding
                  and can pick a language first. The popup itself also
                  applies an admin-controlled delay (popup_delay_seconds)
                  so the admin can log in even if a forced update is set. */}
              {!showSplash && !showLangPicker && <UpdatePopup />}
              {/* FEATURE (2026-01) — Smart-TV "house ad" banner.
                  AdMob is mobile-only, so on Tizen / webOS the bottom
                  banner slot is filled by an admin-configured HTML
                  snippet or image link instead. The component is a
                  no-op on every other platform. */}
              {!showSplash && !showLangPicker && <TVBanner />}
              {/* TV-only guest lockout. Renders as a top-level overlay
                  with z-index 10000 so it sits ABOVE every page (Welcome,
                  Live TV, Movies, …) the moment the device-level 15-day
                  trial has run out on Samsung Tizen / LG webOS. Premium
                  users, admins, Android phones and the web preview are
                  never affected. */}
              {!showSplash && !showLangPicker && <TVGuestLockOverlay />}
              {/* TV-only persistent "X days left" badge. Mounts at the
                  top-right corner of the screen and counts down 15 → 0
                  during the free trial. Disappears at 0 (the lock
                  overlay above replaces it). Hidden for non-TV
                  platforms, admins and premium users. */}
              {!showSplash && !showLangPicker && <TVTrialBadge />}
            </Router>
            </EntitlementProvider>
          </AuthProvider>
        </FocusProvider>
      </TooltipProvider>
    </QueryClientProvider>
  );
};

export default App;
