import type { ErrorInfo, ReactNode } from "react";
import { Component, lazy, Suspense } from "react";
import { Redirect, Route, Router, Switch } from "wouter";
// Eagerly loaded (needed on every page)
import { CriticalDataGate } from "./components/CriticalDataGate.tsx";
import { ResponsiveLayout } from "./components/ResponsiveLayout.tsx";
import { ActiveDeckProvider } from "./contexts/ActiveDeckContext.tsx";
import { GenerationQueueProvider } from "./contexts/GenerationQueueContext.tsx";
import { SubscriptionProvider } from "./contexts/SubscriptionContext.tsx";
import { UserProvider, useUser } from "./contexts/UserContext.tsx";
import { errorReporter } from "./lib/error-reporter.ts";

// Wraps lazy() to handle stale chunk errors after deploys.
// When a dynamic import fails (e.g. old cached HTML references a chunk that
// no longer exists), reload the page once to pick up the new HTML + chunks.
function lazyWithRetry<T extends { default: React.ComponentType<any> }>(
  factory: () => Promise<T>,
): React.LazyExoticComponent<T["default"]> {
  return lazy(() =>
    factory().catch((error: unknown) => {
      const alreadyRetried = sessionStorage.getItem("chunk_retry");
      if (!alreadyRetried) {
        sessionStorage.setItem("chunk_retry", "1");
        globalThis.location.reload();
        // Return a never-resolving promise so React doesn't render the error
        return new Promise<T>(() => {});
      }
      // Already retried once — surface the real error
      sessionStorage.removeItem("chunk_retry");
      throw error;
    }),
  );
}

// Lazy-loaded route components (only fetched when navigated to)
// Each uses named→default adapter since Biome converts to named exports
const AuthScreen = lazyWithRetry(() =>
  import("./components/AuthScreen.tsx").then((m) => ({ default: m.AuthScreen })),
);
const Settings = lazyWithRetry(() =>
  import("./components/Settings.tsx").then((m) => ({ default: m.Settings })),
);
const FlashcardsPage = lazyWithRetry(() =>
  import("./components/FlashcardsPage.tsx").then((m) => ({ default: m.FlashcardsPage })),
);
const LandingPage = lazyWithRetry(() =>
  import("./components/LandingPage.tsx").then((m) => ({ default: m.LandingPage })),
);
const WelcomePage = lazyWithRetry(() =>
  import("./components/WelcomePage.tsx").then((m) => ({ default: m.WelcomePage })),
);
const ForgotPassword = lazyWithRetry(() =>
  import("./components/ForgotPassword.tsx").then((m) => ({ default: m.ForgotPassword })),
);
const ResetPassword = lazyWithRetry(() =>
  import("./components/ResetPassword.tsx").then((m) => ({ default: m.ResetPassword })),
);
const PracticePage = lazyWithRetry(() =>
  import("./components/PracticePage.tsx").then((m) => ({ default: m.PracticePage })),
);
const OnboardingWelcome = lazyWithRetry(() =>
  import("./components/OnboardingWelcome.tsx").then((m) => ({ default: m.OnboardingWelcome })),
);
const OnboardingDemo = lazyWithRetry(() =>
  import("./components/OnboardingDemo.tsx").then((m) => ({ default: m.OnboardingDemo })),
);
const OnboardingDone = lazyWithRetry(() =>
  import("./components/OnboardingDone.tsx").then((m) => ({ default: m.OnboardingDone })),
);
const OnboardingReviewMethod = lazyWithRetry(() =>
  import("./components/onboarding/OnboardingReviewMethod.tsx").then((m) => ({
    default: m.OnboardingReviewMethod,
  })),
);
const DeckConfigPage = lazyWithRetry(() =>
  import("./components/DeckConfigPage.tsx").then((m) => ({ default: m.DeckConfigPage })),
);
const HelpPage = lazyWithRetry(() =>
  import("./components/HelpPage.tsx").then((m) => ({ default: m.HelpPage })),
);
const SupportPage = lazyWithRetry(() =>
  import("./components/SupportPage.tsx").then((m) => ({ default: m.SupportPage })),
);
const ChangelogPage = lazyWithRetry(() =>
  import("./components/ChangelogPage.tsx").then((m) => ({ default: m.ChangelogPage })),
);
const VerifyEmailScreen = lazyWithRetry(() =>
  import("./components/VerifyEmailScreen.tsx").then((m) => ({ default: m.VerifyEmailScreen })),
);
const VerifyEmailPage = lazyWithRetry(() =>
  import("./components/VerifyEmailPage.tsx").then((m) => ({ default: m.VerifyEmailPage })),
);
const AdminDashboard = lazyWithRetry(() =>
  import("./components/AdminDashboard.tsx").then((m) => ({ default: m.AdminDashboard })),
);
const PackSelection = lazyWithRetry(() =>
  import("./components/onboarding/PackSelection.tsx").then((m) => ({
    default: m.PackSelection,
  })),
);
const DevComponentsPage = lazyWithRetry(() =>
  import("./components/DevComponentsPage.tsx").then((m) => ({
    default: m.DevComponentsPage,
  })),
);
const StoriesPage = lazyWithRetry(() =>
  import("./components/stories/StoriesPage.tsx").then((m) => ({ default: m.StoriesPage })),
);
const StoryReaderPage = lazyWithRetry(() =>
  import("./components/stories/StoryReaderPage.tsx").then((m) => ({ default: m.StoryReaderPage })),
);

function useIsLocalDev() {
  return typeof window !== "undefined" && window.location.hostname === "localhost";
}

// Lazy-loaded banner — only fetched when user is unverified
const EmailVerificationBanner = lazyWithRetry(() =>
  import("./components/EmailVerificationBanner.tsx").then((m) => ({
    default: m.EmailVerificationBanner,
  })),
);

function AuthenticatedRoutes() {
  const { user } = useUser();

  return (
    <ResponsiveLayout>
      <Suspense fallback={null}>
        <Switch>
          <Route path="/" component={WelcomePage} />
          <Route path="/cards" component={() => <Redirect to="/flashcards?tab=cards" />} />
          <Route path="/flashcards" component={FlashcardsPage} />
          <Route path="/practice" component={PracticePage} />
          <Route path="/stories" component={StoriesPage} />
          <Route path="/stories/:slug/chapters/:num" component={StoryReaderPage} />
          <Route path="/sentence-builder" component={() => <Redirect to="/practice?tab=write" />} />
          <Route path="/progress" component={() => <Redirect to="/practice?tab=history" />} />
          <Route
            path="/practice-history"
            component={() => <Redirect to="/practice?tab=history" />}
          />
          <Route
            path="/settings"
            component={() => (user ? <Settings /> : <Redirect to="/auth" />)}
          />
          <Route path="/profile" component={() => <Redirect to="/settings" />} />
          <Route path="/email-settings" component={() => <Redirect to="/deck-config" />} />
          <Route path="/deck-config" component={DeckConfigPage} />
          <Route
            path="/admin"
            component={() => (user?.isAdmin ? <AdminDashboard /> : <Redirect to="/" />)}
          />
          <Route path="/welcome" component={() => <Redirect to="/" />} />
          <Route component={() => <Redirect to="/" />} />
        </Switch>
      </Suspense>
    </ResponsiveLayout>
  );
}

function AppContent() {
  // Clear stale chunk retry flag on successful render
  if (sessionStorage.getItem("chunk_retry")) sessionStorage.removeItem("chunk_retry");
  const { user, isAuthenticated, handleLogin, handleLogout: _handleLogout } = useUser();
  const isLocalDev = useIsLocalDev();

  // Check if user needs onboarding
  const needsOnboarding = isAuthenticated && user && !user.onboardingCompleted;

  // Check if user needs email verification (new users only — required=true)
  const needsVerification =
    isAuthenticated && user && !user.emailVerified && user.emailVerificationRequired;

  // Show banner for existing unverified users (required=false)
  const showVerificationBanner =
    isAuthenticated && user && !user.emailVerified && !user.emailVerificationRequired;

  const router = (
    <Router>
      <Switch>
        {/* Dev component gallery — localhost only, must be first in Switch */}
        <Route
          path="/dev"
          component={() =>
            isLocalDev ? (
              <ResponsiveLayout hideNavigation>
                <DevComponentsPage />
              </ResponsiveLayout>
            ) : (
              <Redirect to="/" />
            )
          }
        />

        {/* Help page - accessible in all auth states */}
        <Route
          path="/help"
          component={() => {
            const showNav = isAuthenticated && !needsOnboarding;
            return (
              <ResponsiveLayout hideNavigation={!showNav}>
                <HelpPage />
              </ResponsiveLayout>
            );
          }}
        />

        {/* Support page - accessible in all auth states */}
        <Route
          path="/support"
          component={() => {
            const showNav = isAuthenticated && !needsOnboarding;
            return (
              <ResponsiveLayout hideNavigation={!showNav}>
                <SupportPage />
              </ResponsiveLayout>
            );
          }}
        />

        {/* Changelog - accessible in all auth states */}
        <Route
          path="/changelog"
          component={() => {
            const showNav = isAuthenticated && !needsOnboarding && !needsVerification;
            return (
              <ResponsiveLayout hideNavigation={!showNav}>
                <ChangelogPage />
              </ResponsiveLayout>
            );
          }}
        />

        {/* Email verification page - accessible in all auth states */}
        <Route
          path="/auth/verify-email"
          component={() => (
            <ResponsiveLayout hideNavigation>
              <VerifyEmailPage />
            </ResponsiveLayout>
          )}
        />

        {/* Verification required for new users */}
        {needsVerification && (
          <>
            <Route
              path="/"
              component={() => (
                <ResponsiveLayout hideNavigation>
                  <VerifyEmailScreen />
                </ResponsiveLayout>
              )}
            />
            <Route
              component={() => (
                <ResponsiveLayout hideNavigation>
                  <VerifyEmailScreen />
                </ResponsiveLayout>
              )}
            />
          </>
        )}

        {/* Public routes */}
        {!isAuthenticated && (
          <>
            <Route
              path="/onboarding"
              component={() => (
                <ResponsiveLayout hideNavigation>
                  <OnboardingWelcome />
                </ResponsiveLayout>
              )}
            />
            <Route
              path="/onboarding/account"
              component={() => (
                <ResponsiveLayout hideNavigation>
                  <AuthScreen onLogin={handleLogin} isOnboarding />
                </ResponsiveLayout>
              )}
            />
            {/* Unauthenticated users trying to access later steps → create account first */}
            <Route
              path="/onboarding/demo"
              component={() => <Redirect to="/onboarding/account" />}
            />
            <Route
              path="/onboarding/review-method"
              component={() => <Redirect to="/onboarding/account" />}
            />
            <Route
              path="/auth"
              component={() => (
                <ResponsiveLayout hideNavigation>
                  <AuthScreen onLogin={handleLogin} />
                </ResponsiveLayout>
              )}
            />
            <Route
              path="/auth/forgot-password"
              component={() => (
                <ResponsiveLayout hideNavigation>
                  <ForgotPassword />
                </ResponsiveLayout>
              )}
            />
            <Route
              path="/auth/reset-password"
              component={() => (
                <ResponsiveLayout hideNavigation>
                  <ResetPassword />
                </ResponsiveLayout>
              )}
            />
            <Route
              path="/"
              component={() => (
                <ResponsiveLayout hideNavigation>
                  <LandingPage />
                </ResponsiveLayout>
              )}
            />
            <Route component={() => <Redirect to="/" />} />
          </>
        )}

        {/* Onboarding routes for authenticated users who haven't completed onboarding */}
        {isAuthenticated && needsOnboarding && !needsVerification && (
          <>
            <Route
              path="/onboarding"
              component={() => (
                <ResponsiveLayout hideNavigation>
                  <OnboardingWelcome />
                </ResponsiveLayout>
              )}
            />
            <Route path="/onboarding/account" component={() => <Redirect to="/onboarding" />} />
            <Route
              path="/onboarding/demo"
              component={() => (
                <ResponsiveLayout hideNavigation>
                  <OnboardingDemo />
                </ResponsiveLayout>
              )}
            />
            <Route
              path="/onboarding/review-method"
              component={() => (
                <ResponsiveLayout hideNavigation>
                  <OnboardingReviewMethod />
                </ResponsiveLayout>
              )}
            />
            <Route
              path="/onboarding/packs"
              component={() => (
                <ResponsiveLayout hideNavigation>
                  <PackSelection />
                </ResponsiveLayout>
              )}
            />
            <Route
              path="/onboarding/done"
              component={() => (
                <ResponsiveLayout hideNavigation>
                  <OnboardingDone />
                </ResponsiveLayout>
              )}
            />
            <Route path="/" component={() => <Redirect to="/onboarding" />} />
            <Route component={() => <Redirect to="/onboarding" />} />
          </>
        )}

        {/* Protected routes for users who have completed onboarding */}
        {isAuthenticated && !needsOnboarding && !needsVerification && (
          <Route component={AuthenticatedRoutes} />
        )}
      </Switch>
    </Router>
  );

  return (
    <div className="min-h-screen bg-slate-50 font-sans">
      {showVerificationBanner && (
        <Suspense fallback={null}>
          <EmailVerificationBanner />
        </Suspense>
      )}
      <Suspense fallback={null}>
        {isAuthenticated ? (
          <SubscriptionProvider>
            <ActiveDeckProvider>
              <CriticalDataGate>{router}</CriticalDataGate>
            </ActiveDeckProvider>
          </SubscriptionProvider>
        ) : (
          router
        )}
      </Suspense>
    </div>
  );
}

class SentryErrorBoundary extends Component<{ children: ReactNode }, { hasError: boolean }> {
  override state = { hasError: false };

  static getDerivedStateFromError() {
    return { hasError: true };
  }

  override componentDidCatch(error: Error, info: ErrorInfo) {
    errorReporter.capture(error, {
      boundary: "SentryErrorBoundary",
      componentStack: info.componentStack,
    });
  }

  override render() {
    if (this.state.hasError) {
      return (
        <div
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            height: "100vh",
            flexDirection: "column",
            gap: "12px",
            fontFamily: "'Noto Sans', system-ui, sans-serif",
            color: "#475569",
          }}
        >
          <div style={{ fontSize: "48px" }}>🐻</div>
          <div style={{ fontSize: "16px", fontWeight: 500 }}>Something went wrong</div>
          <button
            type="button"
            onClick={() => globalThis.location.reload()}
            style={{
              padding: "8px 20px",
              background: "#f59e0b",
              color: "white",
              border: "none",
              borderRadius: "8px",
              fontWeight: 600,
              cursor: "pointer",
            }}
          >
            Reload
          </button>
        </div>
      );
    }
    return this.props.children;
  }
}

export function App() {
  return (
    <SentryErrorBoundary>
      <UserProvider>
        <GenerationQueueProvider>
          <AppContent />
        </GenerationQueueProvider>
      </UserProvider>
    </SentryErrorBoundary>
  );
}
