import { AppLayout, type SidebarItem } from "@/components/AppLayout";
import { useDisclosure } from "@mantine/hooks";
import {
  Home,
  Layers,
  LifeBuoy,
  Loader2,
  // MapPin,
  Package,
  Receipt,
  Settings,
} from "lucide-react";
import { useEffect, useRef } from "react";
import {
  Navigate,
  Outlet,
  Route,
  Routes,
  useLocation,
  useNavigate,
} from "react-router-dom";

import OnboardingResumeBanner, {
  AccountReviewBanner,
} from "./components/onboarding/OnboardingResumeBanner";
import OnboardingWizardDialog from "./components/onboarding/OnboardingWizardDialog";
import { ApiErrorModal } from "./components/errors/ApiErrorModal";
import useAuth from "./hooks/useAuth";
import { useIdentify } from "./lib/posthog";
import {
  startTokenRefreshScheduler,
  stopTokenRefreshScheduler,
} from "./utils/refreshScheduler";
import EDRFreightLandingPage from "./pages/EDRFreightLandingPage";
import MyPortalPage from "./pages/MyPortalPage";
import MySignaturePage from "./pages/MySignaturePage";
import SettingsPage from "./pages/SettingsPage";
import ForgotPasswordPage from "./pages/accounts/ForgotPasswordPage";
import ResetPasswordLinkPage from "./pages/accounts/ResetPasswordLinkPage";
import LoginPage from "./pages/accounts/LoginPage";
import SetPasswordPage from "./pages/accounts/SetPasswordPage";
import SignupPage from "./pages/accounts/SignupPage";
import VerificationOtpPage from "./pages/accounts/VerificationOtpPage";
import InvoiceDetailPage from "./pages/billing/InvoiceDetailPage";
import InvoicesList from "./pages/billing/InvoicesList";
import BookingContractPage from "./pages/bookings/BookingContractPage";
import BookingDetailPage from "./pages/bookings/BookingDetailPage";
import BookingsListPage from "./pages/bookings/BookingsListPage";
import EditBookingPage from "./pages/bookings/EditBookingPage";
import LastMileConfirmPage from "./pages/bookings/last-mile-confirm/LastMileConfirmPage";
import LastMileContractPage from "./pages/bookings/last-mile-contract/LastMileContractPage";
import ContractDetailPage from "./pages/contracts/ContractDetailPage";
import ContractViewPage from "./pages/contracts/ContractViewPage";
import ContractsList from "./pages/contracts/ContractsList";
import NewContractPage from "./pages/contracts/NewContractPage";
import NewShipmentPage from "./pages/contracts/NewShipmentPage";
import NewShipmentRequestPage from "./pages/contracts/NewShipmentRequestPage";
import CheckPaymentPage from "./pages/payments/CheckPaymentPage";
import PaymentFailurePage from "./pages/payments/PaymentFailurePage";
import FaydaCallbackPage from "./pages/FaydaCallbackPage";
import PaymentSuccessPage from "./pages/payments/PaymentSuccessPage";
import {
  ShippingLineBookingDetailPage,
  ShippingLineBookingsPage,
  ShippingLineCompletePage,
  ShippingLineHelpPage,
  ShippingLineHomePage,
  ShippingLineInvoicesPage,
  ShippingLineSettingsPage,
} from "./pages/shipping-line";
import FaqPage from "./pages/support/FaqPage";
import HelpPage from "./pages/support/HelpPage";
import PrivacyPolicyPage from "./pages/support/PrivacyPolicyPage";
import TermsPage from "./pages/support/TermsPage";
import TrackingPage from "./pages/tracking/TrackingPage";

function FullScreenSpinner() {
  return (
    <div className="flex items-center justify-center h-screen">
      <Loader2 className="animate-spin text-primary" />
    </div>
  );
}

function LogoutHandler() {
  const { logout } = useAuth();
  const navigate = useNavigate();
  const hasRun = useRef(false);

  useEffect(() => {
    if (hasRun.current) return;
    hasRun.current = true;
    logout().then(() => navigate("/login", { replace: true }));
  }, []);

  return <FullScreenSpinner />;
}

/** Blocks unauthenticated users; renders children only with a valid session. */
function RequireAuth() {
  const { isPending, isAuthenticated } = useAuth();
  const location = useLocation();

  if (isPending) return <FullScreenSpinner />;
  if (!isAuthenticated)
    return <Navigate to="/login" replace state={{ from: location }} />;
  return <Outlet />;
}

/**
 * Waits for the company query so downstream routes can rely on it being
 * resolved. Onboarding is enforced by OnboardingGate, not here.
 */
function RequireCompany() {
  const { customerQuery } = useAuth();

  if (customerQuery.isPending) return <FullScreenSpinner />;
  return <Outlet />;
}

/**
 * Routes an un-onboarded user may still visit. The wizard auto-opens but is
 * dismissable, so they can browse these freely; any other route forces the
 * wizard back open and bounces them home.
 */
const ONBOARDING_ALLOWED_PATHS = ["/portal", "/signature"];

function isOnboardingAllowedPath(pathname: string): boolean {
  const path = pathname.toLowerCase();
  return ONBOARDING_ALLOWED_PATHS.some(
    (p) => path === p || path.startsWith(p + "/"),
  );
}

/**
 * Enforces first-run onboarding. The home (dashboard) and signature pages stay
 * reachable while onboarding is incomplete; the wizard auto-opens on login but
 * can be dismissed to use those pages. Visiting any other page bounces back to
 * home and re-opens the wizard. New users (no company yet) are treated the same
 * as users who haven't completed onboarding.
 *
 * Shipping lines are exempt: staff register them with their details already
 * captured, so there is nothing for them to onboard — they go straight to home.
 */
function OnboardingGate() {
  const { company, onboardingCompleted, isShippingLine } = useAuth();
  const location = useLocation();

  // Keyed off a positive shipping-line identification, never off "no company":
  // that is also true mid-fetch and on error, which would let customers slip
  // past onboarding whenever the request failed.
  const needsOnboarding = isShippingLine
    ? false
    : !company || !onboardingCompleted;
  const allowedHere = isOnboardingAllowedPath(location.pathname);

  // Open by default while onboarding is pending (covers the login case).
  const [wizardOpen, { open: openWizard, close: closeWizard }] =
    useDisclosure(false);

  // Re-evaluate on every navigation: force the wizard open on blocked routes,
  // and auto-open on first arrival while onboarding is pending.
  useEffect(() => {
    if (needsOnboarding && !allowedHere) {
      openWizard();
    }
  }, [needsOnboarding, allowedHere, location.pathname, openWizard]);

  // Auto-open once when onboarding becomes/loads as pending (login).
  const autoOpenedRef = useRef(false);
  useEffect(() => {
    if (needsOnboarding && !autoOpenedRef.current) {
      autoOpenedRef.current = true;
      openWizard();
    }
    if (!needsOnboarding) autoOpenedRef.current = false;
  }, [needsOnboarding, openWizard]);

  if (needsOnboarding && !allowedHere) {
    return <Navigate to="/portal" replace />;
  }

  return (
    <>
      {needsOnboarding && <OnboardingResumeBanner onResume={openWizard} />}
      {!needsOnboarding && <AccountReviewBanner />}
      <Outlet />
      <OnboardingWizardDialog
        opened={needsOnboarding && wizardOpen}
        onClose={closeWizard}
      />
    </>
  );
}

/**
 * Customer-only routes. A shipping line that lands on one (an old link, a
 * bookmark, a hand-typed URL) is sent to its own home rather than shown a
 * contract/company-shaped page that has no meaning for it.
 */
function RequireCustomer() {
  const { isShippingLine, customerQuery } = useAuth();

  // RequireCompany already awaits this query, but guard anyway: a refetch can
  // flip `isPending` back on, and redirecting on a half-loaded account would
  // throw the user into the wrong app.
  if (customerQuery.isPending) return <FullScreenSpinner />;
  if (isShippingLine) return <Navigate to="/shipping-line" replace />;
  return <Outlet />;
}

/** The mirror of RequireCustomer: shipping-line routes, closed to customers. */
function RequireShippingLine() {
  const { isShippingLine, customerQuery } = useAuth();

  if (customerQuery.isPending) return <FullScreenSpinner />;
  if (!isShippingLine) return <Navigate to="/portal" replace />;
  return <Outlet />;
}

/**
 * Where a signed-in account belongs. Shipping lines and customers have separate
 * apps, so every "you're already logged in" redirect has to pick between them.
 * Waits for the company query: `isShippingLine` is false while that request is
 * still in flight, which would land a shipping line on the customer home first.
 */
function useHomeRoute(): { ready: boolean; href: string } {
  const { isShippingLine, customerQuery } = useAuth();

  return {
    ready: !customerQuery.isPending,
    href: isShippingLine ? "/shipping-line" : "/portal",
  };
}

/** Keeps authenticated users off the login/signup pages. */
function RedirectIfAuthed() {
  const { isPending, isAuthenticated } = useAuth();
  const home = useHomeRoute();

  if (isPending) return <FullScreenSpinner />;
  if (isAuthenticated) {
    if (!home.ready) return <FullScreenSpinner />;
    return <Navigate to={home.href} replace />;
  }
  return <Outlet />;
}

/** Landing page for visitors; authenticated users go straight to the portal. */
function LandingRoute() {
  const { isPending, isAuthenticated } = useAuth();
  const home = useHomeRoute();

  if (isPending) return <FullScreenSpinner />;
  if (isAuthenticated) {
    if (!home.ready) return <FullScreenSpinner />;
    return <Navigate to={home.href} replace />;
  }
  return <EDRFreightLandingPage />;
}

const sidebarItems: SidebarItem[] = [
  { label: "Home", href: "/portal", icon: <Home size={18} /> },
  {
    label: "Contracts",
    href: "/contracts",
    icon: <Layers size={18} />,
  },
  {
    label: "Bookings",
    href: "/bookings",
    icon: <Package size={18} />,
  },
  // {
  //   label: "Tracking",
  //   href: "/tracking",
  //   icon: <MapPin size={18} />,
  // },
  {
    label: "Invoices",
    href: "/billing",
    icon: <Receipt size={18} />,
  },
  {
    section: "Account",
    label: "Settings",
    href: "/settings",
    icon: <Settings size={18} />,
  },
  {
    section: "Account",
    label: "Help & Support",
    href: "/help",
    icon: <LifeBuoy size={18} />,
  },
];

/**
 * Sidebar for shipping lines. Intentionally its own list rather than a filtered
 * view of `sidebarItems`: shipping lines have no contracts, and their Home /
 * Bookings / Invoices pages are different pages at different routes.
 */
const shippingLineSidebarItems: SidebarItem[] = [
  { label: "Home", href: "/shipping-line", icon: <Home size={18} /> },
  {
    label: "Bookings",
    href: "/shipping-line/bookings",
    icon: <Package size={18} />,
  },
  {
    label: "Invoices",
    href: "/shipping-line/invoices",
    icon: <Receipt size={18} />,
  },
  {
    section: "Account",
    label: "Settings",
    href: "/shipping-line/settings",
    icon: <Settings size={18} />,
  },
  {
    section: "Account",
    label: "Help & Support",
    href: "/shipping-line/help",
    icon: <LifeBuoy size={18} />,
  },
];

const App = () => {
  const navigate = useNavigate();
  const location = useLocation();
  const {
    user,
    company,
    companyType,
    createProfile,
    reapplyProfile,
    isAuthenticated,
    isShippingLine,
  } = useAuth();

  // Attribute replays and exceptions to the signed-in user (id/org only).
  useIdentify(user, company);

  // Keep the server session alive while a user is logged in. Runs after
  // login, signup, and page-reload bootstrap alike.
  useEffect(() => {
    if (!isAuthenticated) {
      stopTokenRefreshScheduler();
      return;
    }

    startTokenRefreshScheduler();
    return stopTokenRefreshScheduler;
  }, [isAuthenticated]);

  const displayName = user?.name?.en || user?.username || user?.email || "User";
  const userEmail = user?.email;
  const companyProfiles = company?.company?.companyProfiles ?? [];

  return (
    <>
      {/* Global API error modal — shows the server's actual error message for
          every failed request (suppressed on onboarding/auth pages). */}
      <ApiErrorModal />
      <Routes>
        {/* Public routes */}
        <Route index element={<LandingRoute />} />
        <Route path="/logout" element={<LogoutHandler />} />
        <Route
          path="/booking/check-status/:orderId"
          element={<CheckPaymentPage />}
        />
        {/* Payment provider browser redirects (PAYMENT_RETURN_URL / PAYMENT_FAILURE_URL) */}
        {/* Fayda (eSignet) redirect_uri — the whole tab lands here after
          verification, completes the code/state exchange and navigates back
          to the page that started it. Public on purpose: behind RequireAuth
          the onboarding gate would redirect away before the exchange ran. */}
        <Route path="/fayda/callback" element={<FaydaCallbackPage />} />
        <Route path="/callback" element={<FaydaCallbackPage />} />
        <Route path="/payment/success" element={<PaymentSuccessPage />} />
        <Route path="/payment/failure" element={<PaymentFailurePage />} />

        {/* Help and legal pages. Public on purpose: the auth screens link to
          them before a session exists, so they carry their own chrome rather
          than sitting inside the authenticated app layout. */}
        <Route path="/help" element={<HelpPage />} />
        <Route path="/faq" element={<FaqPage />} />
        <Route path="/privacy" element={<PrivacyPolicyPage />} />
        <Route path="/terms" element={<TermsPage />} />

        {/* Auth pages — inaccessible once logged in */}
        <Route element={<RedirectIfAuthed />}>
          <Route path="/login" element={<LoginPage />} />
          <Route path="/signup" element={<SignupPage />} />
          <Route path="/forgot-password" element={<ForgotPasswordPage />} />
        </Route>

        {/* Staff-issued reset links land here. Deliberately outside
          RedirectIfAuthed: a customer with a stale session still needs the link
          to work, and the token — not the session — is what authorises it. */}
        <Route path="/reset-password" element={<ResetPasswordLinkPage />} />

        {/* Signup-flow pages; reached while a session already exists */}
        <Route path="/otp" element={<VerificationOtpPage />} />
        <Route path="/set-password" element={<SetPasswordPage />} />

        <Route element={<RequireAuth />}>
          <Route element={<RequireCompany />}>
            {/* Shipping-line app. Its own layout and sidebar, and its own pages
              at their own routes — nothing here is shared with the customer
              branch below beyond the shell component itself. Contracts are
              absent by design: shipping lines request bookings directly. */}
            {isShippingLine && (
              <Route element={<RequireShippingLine />}>
                <Route
                  element={
                    <AppLayout
                      title="EDR Freight"
                      sidebarItems={shippingLineSidebarItems}
                      activeHref={location.pathname}
                      onNavigate={navigate}
                      userName={displayName}
                      userEmail={userEmail}
                      // Support chat is company-scoped; a shipping line has no
                      // company, so every poll would 403.
                      showSupportWidget={false}
                    >
                      <Outlet />
                    </AppLayout>
                  }
                >
                  <Route
                    path="/shipping-line"
                    element={<ShippingLineHomePage />}
                  />
                  <Route
                    path="/shipping-line/bookings"
                    element={<ShippingLineBookingsPage />}
                  />
                  <Route
                    path="/shipping-line/bookings/:id"
                    element={<ShippingLineBookingDetailPage />}
                  />
                  <Route
                    path="/shipping-line/bookings/:id/complete"
                    element={<ShippingLineCompletePage />}
                  />
                  <Route
                    path="/shipping-line/invoices"
                    element={<ShippingLineInvoicesPage />}
                  />
                  {/* Same detail component as the customer's /billing/:id — the
                    API scopes my-invoices to the signed-in payer either way,
                    and the page derives its back target from the URL. */}
                  <Route
                    path="/shipping-line/invoices/:id"
                    element={<InvoiceDetailPage />}
                  />
                  <Route
                    path="/shipping-line/settings"
                    element={<ShippingLineSettingsPage />}
                  />
                  <Route
                    path="/shipping-line/settings"
                    element={<ShippingLineSettingsPage />}
                  />
                  <Route
                    path="/shipping-line/help"
                    element={<ShippingLineHelpPage />}
                  />
                  {/* Old shared links land on the shipping-line equivalents. */}
                  <Route
                    path="/settings"
                    element={<Navigate to="/shipping-line/settings" replace />}
                  />
                </Route>
              </Route>
            )}

            {/* Customer app — unchanged. */}
            <Route element={<RequireCustomer />}>
              <Route
                element={
                  <AppLayout
                    title="EDR Freight"
                    sidebarItems={sidebarItems}
                    activeHref={location.pathname}
                    onNavigate={navigate}
                    userName={displayName}
                    userEmail={userEmail}
                    companyProfiles={companyProfiles}
                    companyType={companyType}
                    onCreateProfile={createProfile}
                    onReapplyProfile={reapplyProfile}
                  >
                    <OnboardingGate />
                  </AppLayout>
                }
              >
                <Route path="/portal" element={<MyPortalPage />} />
                {/* Bookings are created against a contract, but the full list is
                browsable here. New-booking entry still routes via a contract. */}
                <Route path="/bookings" element={<BookingsListPage />} />
                <Route
                  path="/bookings/new"
                  element={<Navigate to="/contracts/new" replace />}
                />
                <Route
                  path="/bookings/:id/edit"
                  element={<EditBookingPage />}
                />
                <Route path="/bookings/:id" element={<BookingDetailPage />} />
                <Route
                  path="/bookings/:id/last-mile-confirm"
                  element={<LastMileConfirmPage />}
                />
                <Route
                  path="/bookings/:id/last-mile-contract"
                  element={<LastMileContractPage />}
                />
                <Route
                  path="/bookings/:id/contract"
                  element={<BookingContractPage />}
                />
                <Route path="/contracts" element={<ContractsList />} />
                <Route path="/contracts/new" element={<NewContractPage />} />
                <Route
                  path="/contracts/:id/edit"
                  element={<NewContractPage mode="edit" />}
                />
                <Route
                  path="/contracts/:id/shipment-requests/new"
                  element={<NewShipmentRequestPage />}
                />
                <Route
                  path="/contracts/:id/bookings/new"
                  element={<NewShipmentPage />}
                />
                {/* Completion of an initiated (bare) booking after per-booking
                clearance — same form, submits to the complete endpoint. */}
                <Route
                  path="/contracts/:id/bookings/:bookingId/complete"
                  element={<NewShipmentPage />}
                />
                <Route
                  path="/contracts/:id/view"
                  element={<ContractViewPage />}
                />
                <Route path="/contracts/:id" element={<ContractDetailPage />} />
                <Route path="/tracking" element={<TrackingPage />} />
                <Route path="/billing" element={<InvoicesList />} />
                <Route path="/billing/:id" element={<InvoiceDetailPage />} />
                {/* Profile was merged into Settings — keep old links working. */}
                <Route
                  path="/profile"
                  element={<Navigate to="/settings" replace />}
                />
                <Route path="/signature" element={<MySignaturePage />} />
                <Route path="/settings" element={<SettingsPage />} />
              </Route>
            </Route>
          </Route>
        </Route>

        <Route path="*" element={<Navigate to="/" replace />} />
      </Routes>
    </>
  );
};

export default App;
