import { useEffect, useMemo, useState } from "react";
import { Navigate, Route, Routes, useLocation } from "react-router-dom";
import Sidebar from "./components/Sidebar.jsx";
import TopBar from "./components/TopBar.jsx";
import MobileMenu from "./components/MobileMenu.jsx";
import TopicSelector from "./components/TopicSelector.jsx";
import MapView from "./pages/MapView.jsx";
import TimelineView from "./pages/TimelineView.jsx";
import ContrastingGroupsView from "./pages/ContrastingGroupsView.jsx";
import { fetchMeta } from "./api/client.js";
import { DEFAULT_NEWS_TIMEFRAME } from "./constants/timeframes.js";

const STORAGE_KEY = "FrameVis.query.v1";

const DEFAULT_QUERY = {
  topic: "",
  newsTimeframe: DEFAULT_NEWS_TIMEFRAME,
};

function normalizeStoredQuery(raw) {
  try {
    const parsed = JSON.parse(raw);
    return {
      topic: typeof parsed.topic === "string" ? parsed.topic : "",
      newsTimeframe: parsed.newsTimeframe ?? DEFAULT_NEWS_TIMEFRAME,
    };
  } catch {
    return DEFAULT_QUERY;
  }
}

export default function App() {
  const location = useLocation();
  const [query, setQuery] = useState(() => {
    try {
      const raw = localStorage.getItem(STORAGE_KEY);
      if (raw) return { ...DEFAULT_QUERY, ...normalizeStoredQuery(raw) };
    } catch {
      /* ignore */
    }
    return DEFAULT_QUERY;
  });

  const [meta, setMeta] = useState(null);
  const [metaLoading, setMetaLoading] = useState(false);
  const [selectorOpen, setSelectorOpen] = useState(!query.topic);
  const [isCompact, setIsCompact] = useState(() =>
    typeof window !== "undefined" ? window.innerWidth <= 900 : false
  );
  const [sidebarOpen, setSidebarOpen] = useState(true);
  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);

  const topicKey = query.topic?.trim() ?? "";
  const newsTimeframeKey = query.newsTimeframe ?? DEFAULT_NEWS_TIMEFRAME;

  useEffect(() => {
    if (!topicKey) return;
    let cancelled = false;
    setMetaLoading(true);
    const persist = {
      topic: topicKey,
      newsTimeframe: newsTimeframeKey,
    };
    fetchMeta(persist)
      .then((m) => !cancelled && setMeta(m))
      .finally(() => !cancelled && setMetaLoading(false));
    try {
      localStorage.setItem(STORAGE_KEY, JSON.stringify(persist));
    } catch {
      /* ignore quota errors */
    }
    return () => {
      cancelled = true;
    };
  }, [topicKey, newsTimeframeKey]);

  useEffect(() => {
    const onResize = () => setIsCompact(window.innerWidth <= 900);
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);

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

  const hasTopic = Boolean(query.topic);

  const routedViews = useMemo(
    () => (
      <Routes>
        <Route path="/" element={<Navigate to="/map" replace />} />
        <Route path="/map" element={<MapView query={query} />} />
        <Route path="/timeline" element={<TimelineView query={query} />} />
        <Route
          path="/groups"
          element={<ContrastingGroupsView query={query} />}
        />
        <Route path="*" element={<Navigate to="/map" replace />} />
      </Routes>
    ),
    [query]
  );

  return (
    <div className={`app ${!isCompact && !sidebarOpen ? "app--sidebar-hidden" : ""}`}>
      <aside className="app__sidebar">
        <Sidebar />
      </aside>
      <header className="app__topbar">
        <TopBar
          query={query}
          meta={meta}
          metaLoading={metaLoading}
          menuOpen={isCompact ? mobileMenuOpen : sidebarOpen}
          onToggleMenu={() => {
            if (isCompact) {
              setMobileMenuOpen((v) => !v);
            } else {
              setSidebarOpen((v) => !v);
            }
          }}
          onEditTopic={() => setSelectorOpen(true)}
        />
      </header>
      <main className="app__main">
        {hasTopic ? routedViews : <EmptyState onStart={() => setSelectorOpen(true)} />}
      </main>
      <footer className="app__footer">
        <p className="app__footer-text">
          FrameVis prototype · world map, timeline, contrasting groups · news sections below
        </p>
      </footer>

      {isCompact && (
        <MobileMenu open={mobileMenuOpen} onClose={() => setMobileMenuOpen(false)} />
      )}

      {selectorOpen && (
        <TopicSelector
          initialQuery={query}
          onCancel={hasTopic ? () => setSelectorOpen(false) : undefined}
          onSubmit={(next) => {
            setQuery(next);
            setSelectorOpen(false);
          }}
        />
      )}
    </div>
  );
}

function EmptyState({ onStart }) {
  return (
    <div className="empty-state">
      <div className="empty-state__inner">
        <p className="label">FrameVis · Intelligence Terminal</p>
        <h1 className="empty-state__title">
          How is the world telling <em>this</em> story?
        </h1>
        <p className="empty-state__lede">
          Compare how a single conflict, policy, or event is framed across
          countries, sources, and time. Choose a topic to begin.
        </p>
        <button className="primary" onClick={onStart}>
          Define a topic
        </button>
      </div>
    </div>
  );
}
