import type { Metadata, Viewport } from "next";
import "./globals.css";
import { ApiConfigInit } from "./ApiConfigInit";
import { EdgeSwipeBack } from "./EdgeSwipeBack";
import { MetricKeyboardProvider } from "@enode/ui/metric-keyboard/MetricKeyboardProvider";
import { TourProvider } from "@enode/ui/tour/tour-provider";
import { ErrorEngineInit } from "./error-handling/ErrorEngineInit";
import { ActionResolverInit } from "@enode/ui/auth/action-resolver-init";
import { ActionDialogHost } from "@enode/ui/auth/action-dialog-host";
import { AnnouncementHost } from "@enode/ui/announcements/announcement-host";
import { SharedConflictHost } from "./error-handling/redirects/SharedConflictHost";
import { OfflineBanner } from "./error-handling/OfflineBanner";
import { AuthGuard } from "@enode/core/auth-guard";
import { LogoutTransition } from "@enode/ui/logout-transition";
import { LoginTransition } from "@enode/ui/login-transition";
import { Toaster } from "@enode/ui/feedback/toaster";
import { SupportReportHost } from "@enode/ui/feedback/support-report-host";
import { DataPackageTypesLoader } from "@enode/core/data-package-types/DataPackageTypesLoader";
import { DisplayBasesLoader } from "@enode/core/display/DisplayBasesLoader";
import { EquipmentsLoader } from "@enode/core/equipments/EquipmentsLoader";
import { ExerciseVariationsLoader } from "@enode/core/exercise-variations/ExerciseVariationsLoader";
import { FeedbackModesLoader } from "@enode/core/feedback-modes/FeedbackModesLoader";
import { AppLanguagesLoader } from "@enode/core/languages/AppLanguagesLoader";
import { HtmlLangSync } from "@enode/core/locale/HtmlLangSync";
// import { ManualButton } from "@enode/ui/ManualButton";
import { MediaLoader } from "@enode/core/media/MediaLoader";
import { MetricsLoader } from "@enode/core/metrics/MetricsLoader";
import { TagsLoader } from "@enode/core/tags/TagsLoader";
import { TextContentLoader } from "@enode/core/text-content/TextContentLoader";
import { TrackingSettingsLoader } from "@enode/core/tracking/TrackingSettingsLoader";
import { UiTextContentLoader } from "@enode/core/ui-text-content/UiTextContentLoader";
import { UserAppSettingsLoader } from "@enode/core/user-app-settings/UserAppSettingsLoader";
import { RemindersInit } from "./reminders/RemindersInit";
import { PushInit } from "./push/PushInit";
import { PushRouter } from "./push/push-router";
import { LiveEarlierSetsPrompt } from "./workouts/today/live-earlier-sets-prompt";
import { LiveOutboxDrain } from "./workouts/today/live-outbox-drain";
import { LivePresenceKeeper } from "./workouts/today/live-presence-keeper";
import { LiveResultPrompt } from "./workouts/today/live-result-card";
import { LiveSharingPrompt } from "./workouts/today/live-sharing-prompt";

export const metadata: Metadata = {
  title: "Enode Pro",
  description: "Enode tracking web app",
  // Run chromeless (no URL bar) when added to the iOS home screen; the
  // `app/manifest.ts` `display: "standalone"` covers Android.
  appleWebApp: {
    capable: true,
    title: "Enode Pro",
    statusBarStyle: "default",
  },
};

export const viewport: Viewport = {
  // viewport-fit=cover signals iOS Safari / the Capacitor WebView that
  // the page will handle the status-bar / home-indicator safe areas via
  // CSS env() insets itself. Required for `env(safe-area-inset-*)` to
  // return non-zero values on iOS — see globals.css and drawer-stack.tsx
  // for where they're consumed.
  viewportFit: "cover",
  // Native-app feel: lock the visual scale. Combined with the
  // touch-action / user-select rules in globals.css, this disables
  // pinch-zoom and the iOS double-tap-zoom delay. Accessibility
  // trade-off acknowledged — iOS still honours system text scaling for
  // the in-app font sizes.
  initialScale: 1,
  maximumScale: 1,
  userScalable: false,
  themeColor: [
    { media: "(prefers-color-scheme: light)", color: "#ffffff" },
    { media: "(prefers-color-scheme: dark)", color: "#000000" },
  ],
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  // Roobert is loaded via @font-face in globals.css (files in public/fonts/).
  return (
    <html lang="en" className="h-full antialiased">
      <head>
        {/* Boot-time iOS detection. Runs synchronously inline so the
            `.ios` class is on <html> before the first paint — no flash
            of un-themed layout when Capacitor's iOS-only tweaks
            (`ios:px-4`, …) kick in. Capacitor injects `window.Capacitor`
            into the WebView shell before user scripts run, so the
            check is safe at this point. */}
        <script
          dangerouslySetInnerHTML={{
            __html: `try{if(window.Capacitor&&window.Capacitor.getPlatform&&window.Capacitor.getPlatform()==='ios')document.documentElement.classList.add('ios');}catch(_){}`,
          }}
        />
        {/* Boot-time text scale. Re-applies the persisted device-local scale
            (see @enode/core/text-scale) to `--text-scale` before first paint,
            so a scaled app doesn't flash at 100% on launch. Key and clamp
            range mirror text-scale.ts. */}
        <script
          dangerouslySetInnerHTML={{
            __html: `try{var s=parseFloat(localStorage.getItem('enode.textScale'));if(s>=0.85&&s<=1.3&&s!==1)document.documentElement.style.setProperty('--text-scale',String(s));}catch(_){}`,
          }}
        />
      </head>
      {/* `h-full` (not `min-h-full`) so the body is exactly the
          viewport height. Pages that use the flex-column + inner
          `overflow-y-auto` pattern need a fixed-height parent — with a
          min-height the body itself grows beyond the viewport when the
          inner content overflows, and *that* causes the window to
          scroll instead of the inner container (e.g. the today list
          dragging its own header down with it). Every page (incl. the
          welcome / auth flow) fills this fixed height with `flex-1`
          rather than a `min-h-screen`, so the window never scrolls. */}
      <body className="h-full">
        {/* The whole app lives in one shell so the video overlay (portaled to
            <body>, a sibling of this shell) can punch a camera-shaped hole in
            it via clip-path while recording — the app stays visible + dimmed
            around the hole instead of being hidden. See globals.css
            `.camera-active` and video-recording-overlay.tsx. */}
        <div id="app-shell" className="flex h-full flex-col">
          <ApiConfigInit />
          <EdgeSwipeBack />
          <ErrorEngineInit />
          <ActionResolverInit />
          <AuthGuard />
          <LogoutTransition />
          <LoginTransition homeRoute="/workouts/today" />
          <OfflineBanner />
          <AppLanguagesLoader />
          {/* Corrects the statically-baked lang attribute once the active
              locale is known — a static export can't render it server-side. */}
          <HtmlLangSync />
          <TextContentLoader />
          <UiTextContentLoader />
          <MetricsLoader />
          <TrackingSettingsLoader />
          <DisplayBasesLoader />
          <UserAppSettingsLoader />
          <DataPackageTypesLoader />
          <EquipmentsLoader />
          <ExerciseVariationsLoader />
          <FeedbackModesLoader />
          <MediaLoader />
          <TagsLoader />
          {/* Device reminders (native only): the notification-tap handler and
              the scheduling sync. Below the text loaders so a cold start bakes
              translated copy into the OS where it can — see
              docs/device-reminders.md. */}
          <RemindersInit />
          {/* OS push (native only): registers this device so the backend has
              somewhere to send, and acts on what arrives. Beside RemindersInit
              because the two share the same OS permission — see
              docs/push-notifications.md. */}
          <PushInit />
          <PushRouter />
          {/* Spotlight-tour mount point — no tracking tour is authored yet;
              definitions go in src/tours/ when one is (see docs/walkthroughs.md). */}
          <TourProvider>
            <MetricKeyboardProvider>{children}</MetricKeyboardProvider>
          </TourProvider>
          <Toaster />
          <SupportReportHost />
          <ActionDialogHost />
          <SharedConflictHost />
          {/* Backend announcements (maintenance, version / feature
              deprecations) — see docs/announcements.md. */}
          <AnnouncementHost client="tracking" />
          {/* Sends the sets that wait for the live session, on every screen —
              see docs/live-performance-hub.md. */}
          <LiveOutboxDrain />
          {/* Tells the live session that the device is there and whether a
              sensor is connected, on every screen. */}
          <LivePresenceKeeper />
          {/* Asks an athlete whose own device a coach added to a live session
              whether to share — see docs/live-performance-hub.md. */}
          <LiveSharingPrompt />
          {/* Asks once whether the sets of a training that was already running
              when the device joined a live session should be sent too. */}
          <LiveEarlierSetsPrompt />
          {/* Says once that the device's live session has ended, with the
              result of the athletes who lifted on it. */}
          <LiveResultPrompt />
          {/* <ManualButton /> — hidden app-wide for now */}
        </div>
      </body>
    </html>
  );
}
