import { Component, useEffect, useState, type ErrorInfo, type ReactElement, type ReactNode } from "react";
import { Navigate, Route, Routes, useLocation, useNavigate } from "react-router-dom";

import { WalkupProvider, useWalkupContext } from "./hooks/useWalkupContext";
import { useSession } from "./hooks/useSession";
import { DashboardPage } from "./pages/DashboardPage";
import { GamedayPage } from "./pages/GamedayPage";
import { LibraryPage } from "./pages/LibraryPage";
import { ProfilePage } from "./pages/ProfilePage";
import { AdminPage } from "./pages/AdminPage";
import { SignInPage } from "./pages/SignInPage";
import { formatTeamLabel } from "./lib/teamsnapHelpers";
import { useOnlineStatus } from "./hooks/useOnlineStatus";

function getRouteDestinationLabel(pathname: string) {
  switch (pathname) {
    case "/":
      return "your dashboard";
    case "/library":
      return "WalkUp clips";
    case "/gameday":
      return "gameday";
    default:
      return "this page";
  }
}

function getNavbarPageLabel(pathname: string) {
  switch (pathname) {
    case "/":
      return "Home";
    case "/library":
      return "WalkUp Clips";
    case "/gameday":
      return "Gameday";
    case "/profile":
      return "Profile";
    case "/admin":
      return "Admin";
    default:
      return "";
  }
}

function ProtectedRoute({ children }: { children: ReactElement }) {
  const location = useLocation();
  const { data, isLoading } = useSession();
  if (isLoading) {
    return (
      <div className="container-fluid py-4">
        <div className="card shadow-sm">
          <div className="card-body">Loading session...</div>
        </div>
      </div>
    );
  }
  if (!data?.authenticated) {
    return <Navigate to="/signin" replace state={{ from: location }} />;
  }
  return children;
}

function HomeRoute() {
  const walkup = useWalkupContext();

  if (walkup.sessionQuery.isLoading) {
    return (
      <div className="container-fluid py-4">
        <div className="card shadow-sm">
          <div className="card-body">Loading session...</div>
        </div>
      </div>
    );
  }

  if (!walkup.sessionQuery.data?.authenticated) {
    return <SignInPage />;
  }

  return (
    <DashboardPage />
  );
}

function SignInRoute() {
  const walkup = useWalkupContext();

  if (walkup.sessionQuery.isLoading) {
    return (
      <div className="container-fluid py-4">
        <div className="card shadow-sm">
          <div className="card-body">Loading session...</div>
        </div>
      </div>
    );
  }

  if (walkup.sessionQuery.data?.authenticated) {
    return <Navigate to="/" replace />;
  }

  return <SignInPage />;
}

function TeamSelectionRoute({ children }: { children: ReactElement }) {
  return children;
}

function TeamSelectionModal() {
  const location = useLocation();
  const walkup = useWalkupContext();

  if (!walkup.isTeamSnap || !walkup.teamsQuery.isFetched || walkup.hasSelectedTeam) {
    return null;
  }

  return (
    <div
      className="position-fixed top-0 start-0 w-100 h-100 bg-dark bg-opacity-75 d-flex align-items-center justify-content-center p-3"
      role="presentation"
    >
      <section
        className="card shadow-lg border-0 w-100"
        style={{ maxWidth: "920px", maxHeight: "88vh" }}
        role="dialog"
        aria-modal="true"
        aria-labelledby="team-selection-title"
      >
        <div className="card-body d-grid gap-4 overflow-auto p-4 p-lg-5">
          <div className="d-grid gap-2">
            <p className="text-uppercase small text-secondary-emphasis mb-0">Step 2 of 2</p>
            <h2 id="team-selection-title" className="h3 mb-0">
              Pick the team you want to use.
            </h2>
            <p className="text-body-secondary mb-0">
              You are signed in with TeamSnap. Choose a team to continue to {getRouteDestinationLabel(location.pathname)}.
            </p>
          </div>
          <div className="row g-4">
            <div className="col-12 col-lg-8">
              <div className="card shadow-sm h-100">
                <div className="card-body d-grid gap-3">
                  <h3 className="h5 mb-0">Available teams</h3>
                  {walkup.teamsQuery.isLoading ? (
                    <div className="text-body-secondary">Loading teams...</div>
                  ) : (
                    <div className="list-group">
                      {walkup.teamsQuery.data?.map((team) => {
                        const teamId = String(team.id);
                        const selected = teamId === walkup.selectedTeamId;
                        return (
                          <button
                            key={teamId}
                            type="button"
                            className={`list-group-item list-group-item-action d-flex justify-content-between align-items-center text-start${
                              selected ? " active" : ""
                            }`}
                            onClick={() => walkup.selectTeam(teamId)}
                          >
                            <div>
                              <strong>{formatTeamLabel(team)}</strong>
                              <div className={selected ? "text-white-50" : "text-body-secondary"}>Tap to continue</div>
                            </div>
                            <span className={`badge rounded-pill ${selected ? "text-bg-light" : "text-bg-secondary"}`}>
                              {selected ? "Selected" : "Choose"}
                            </span>
                          </button>
                        );
                      })}
                      {!walkup.teamsQuery.data?.length ? (
                        <div className="text-body-secondary">No teams were returned for this account.</div>
                      ) : null}
                    </div>
                  )}
                </div>
              </div>
            </div>
            <div className="col-12 col-lg-4">
              <div className="card bg-body-tertiary border-0 h-100">
                <div className="card-body d-grid gap-3">
                  <h3 className="h5 mb-0">What happens next</h3>
                  <div className="d-grid gap-2 text-body-secondary">
                    <div>1. Sign in with TeamSnap.</div>
                    <div>2. Choose the team you want to manage.</div>
                    <div>3. Continue into the dashboard, WalkUp clips, or game tools.</div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </section>
    </div>
  );
}

class AppErrorBoundary extends Component<{ children: ReactNode }, { errorMessage: string | null }> {
  state = { errorMessage: null };

  static getDerivedStateFromError(error: unknown) {
    return {
      errorMessage: error instanceof Error ? error.message : "Unexpected render error",
    };
  }

  componentDidCatch(error: unknown, errorInfo: ErrorInfo) {
    console.error("WalkUp render error", error, errorInfo);
  }

  render() {
    if (this.state.errorMessage) {
      return (
        <div className="container-fluid py-4">
          <div className="card shadow-sm">
            <div className="card-body d-grid gap-2">
              <h2 className="h4 mb-0">App Error</h2>
              <div className="text-body-secondary">{this.state.errorMessage}</div>
            </div>
          </div>
        </div>
      );
    }
    return this.props.children;
  }
}

function ShellLayout() {
  const [navOpen, setNavOpen] = useState(false);
  const walkup = useWalkupContext();
  const location = useLocation();
  const navigate = useNavigate();
  const isOnline = useOnlineStatus();
  const currentPageLabel = getNavbarPageLabel(location.pathname);
  const showNavbar = walkup.sessionQuery.data?.authenticated === true;
  const showTeamSelectionModal = walkup.isTeamSnap && walkup.teamsQuery.isFetched && !walkup.hasSelectedTeam;
  const shellClassName = showNavbar ? "shell is-authenticated" : "shell is-authless";

  useEffect(() => {
    setNavOpen(false);
  }, [location.pathname]);

  useEffect(() => {
    if (!showTeamSelectionModal) {
      return;
    }

    const previousOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => {
      document.body.style.overflow = previousOverflow;
    };
  }, [showTeamSelectionModal]);

  function goTo(pathname: string) {
    setNavOpen(false);
    navigate(pathname);
  }

  return (
    <div className={shellClassName}>
      {showNavbar ? (
        <nav className="navbar navbar-expand-lg navbar-dark bg-dark shadow-sm sticky-top px-3 py-2" aria-label="Primary">
          <div className="container-fluid">
            <button type="button" className="navbar-brand d-flex align-items-center gap-3 mb-0 btn btn-link p-0 text-decoration-none" onClick={() => goTo("/")}>
              <span className="site-brand-mark" aria-hidden="true">
                <i className="bi bi-person-walking" />
              </span>
              <span className="d-flex flex-column gap-0">
                <span className="fw-semibold fs-4 lh-1 text-white">WalkUp</span>
                {currentPageLabel ? (
                  <span className="navbar-text d-lg-none small lh-1 text-white-50">{currentPageLabel}</span>
                ) : null}
              </span>
            </button>
            <button
              type="button"
              className="navbar-toggler ms-auto"
              aria-expanded={navOpen}
              aria-controls="primary-nav"
              aria-label={navOpen ? "Close menu" : "Open menu"}
              onClick={() => setNavOpen((value) => !value)}
            >
              <span className="navbar-toggler-icon" aria-hidden="true" />
            </button>
            <div id="primary-nav" className={`navbar-collapse collapse${navOpen ? " show" : ""}`}>
              <ul className="navbar-nav ms-auto gap-2">
                <li className="nav-item">
                  <button
                    type="button"
                    className={`nav-link btn btn-link${location.pathname === "/" ? " active" : ""}`}
                    onClick={() => goTo("/")}
                  >
                    Home
                  </button>
                </li>
                <li className="nav-item">
                  <button
                    type="button"
                    className={`nav-link btn btn-link${location.pathname === "/library" ? " active" : ""}`}
                    onClick={() => goTo("/library")}
                  >
                    WalkUp Clips
                  </button>
                </li>
                <li className="nav-item">
                  <button
                    type="button"
                    className={`nav-link btn btn-link${location.pathname === "/gameday" ? " active" : ""}`}
                    onClick={() => goTo("/gameday")}
                  >
                    Gameday
                  </button>
                </li>
                <li className="nav-item">
                  <button
                    type="button"
                    className={`nav-link btn btn-link${location.pathname === "/profile" ? " active" : ""}`}
                    onClick={() => goTo("/profile")}
                  >
                    Profile
                  </button>
                </li>
              </ul>
            </div>
          </div>
        </nav>
      ) : null}
      {!isOnline ? (
        <div className="alert alert-warning rounded-0 border-0 mb-0 py-2 text-center" role="status">
          Offline mode: showing cached clips and previously loaded game data until the connection returns.
        </div>
      ) : null}
      <main className="container-fluid py-4">
        <Routes>
          <Route path="/signin" element={<SignInRoute />} />
          <Route path="/admin" element={<AdminPage />} />
          <Route path="/profile" element={<ProtectedRoute><ProfilePage /></ProtectedRoute>} />
          <Route path="/" element={<HomeRoute />} />
          <Route path="/library" element={<ProtectedRoute><TeamSelectionRoute><LibraryPage /></TeamSelectionRoute></ProtectedRoute>} />
          <Route path="/games" element={<Navigate to="/" replace />} />
          <Route path="/gameday" element={<ProtectedRoute><TeamSelectionRoute><GamedayPage /></TeamSelectionRoute></ProtectedRoute>} />
        </Routes>
      </main>
      {showTeamSelectionModal ? <TeamSelectionModal /> : null}
    </div>
  );
}

export default function App() {
  return (
    <AppErrorBoundary>
      <WalkupProvider>
        <ShellLayout />
      </WalkupProvider>
    </AppErrorBoundary>
  );
}
