// app.jsx — Root app, sidebar, topbar, view routing, persistence.

const { useState, useEffect, useMemo, useRef } = React;

const NAV_ITEMS = [
  { id: "overview",      label: "Overview",       icon: Icons.home,      group: "main" },
  { id: "opportunities", label: "Opportunities",  icon: Icons.briefcase, group: "main", badgeFrom: "opps" },
  { id: "map",           label: "Map",            icon: Icons.map,       group: "main" },
  { id: "pipeline",      label: "Pipeline",       icon: Icons.pipeline,  group: "main", badgeFrom: "pipe" },
  { id: "partners",      label: "Partners",       icon: Icons.users,     group: "main", badgeFrom: "parts" },
  { id: "profile",       label: "Company profile",icon: Icons.building,  group: "you" },
];

const ROUTES = NAV_ITEMS.map((item) => item.id);
const STORAGE = {
  tweaks: "susu-funding:tweaks",
  pipeline: "susu-funding:pipeline",
  activity: "susu-funding:activity",
  bookmarks: "susu-funding:bookmarks",
  intros: "susu-funding:intro-requests",
};

function loadStored(key, fallback) {
  try {
    const raw = localStorage.getItem(key);
    return raw ? JSON.parse(raw) : fallback;
  } catch (err) {
    return fallback;
  }
}

function saveStored(key, value) {
  try {
    localStorage.setItem(key, JSON.stringify(value));
  } catch (err) {
    // Storage can fail in private windows; the app still works in memory.
  }
}

function routeFromHash() {
  const id = window.location.hash.replace(/^#\/?/, "");
  return ROUTES.includes(id) ? id : "overview";
}

function withLiveDeadlines(opportunities) {
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  return opportunities.map((o) => {
    if (o.deadline === "rolling") return { ...o, daysLeft: null };
    const deadline = new Date(`${o.deadline}T00:00:00`);
    return { ...o, daysLeft: Math.ceil((deadline - today) / (1000 * 60 * 60 * 24)) };
  });
}

function Sidebar({ active, go, counts }) {
  const badge = (k) => ({ opps: counts.opportunities, pipe: counts.pipeline, parts: counts.partners }[k]);

  return (
    <aside className="sidebar">
      <div className="brand">
        <div className="brand-mark" />
        <div className="stack gap-2">
          <div className="brand-name">SuSu Funding</div>
          <div className="brand-sub">Intelligence</div>
        </div>
      </div>

      <div className="nav-group">
        <div className="nav-label">Discover</div>
        {NAV_ITEMS.filter(n => n.group === "main").map(n => (
          <button key={n.id} className={"nav-item" + (active === n.id ? " active" : "")} onClick={() => go(n.id)}>
            <Icon d={n.icon} size={16} className="nav-icon" />
            <span>{n.label}</span>
            {n.badgeFrom && <span className="nav-badge">{badge(n.badgeFrom)}</span>}
          </button>
        ))}
      </div>

      <div className="nav-group">
        <div className="nav-label">You</div>
        {NAV_ITEMS.filter(n => n.group === "you").map(n => (
          <button key={n.id} className={"nav-item" + (active === n.id ? " active" : "")} onClick={() => go(n.id)}>
            <Icon d={n.icon} size={16} className="nav-icon" />
            <span>{n.label}</span>
          </button>
        ))}
      </div>

      <div className="sidebar-foot">
        <div className="pulse" />
        <div className="stack gap-2">
          <div style={{color:"var(--text-dim)", fontWeight:500, fontSize:11.5}}>Scanning...</div>
          <div style={{fontSize:10}}>Match engine v2.4</div>
        </div>
      </div>
    </aside>
  );
}

function Topbar({
  active,
  setQuery,
  query,
  searchRef,
  onActivityClick,
  onBookmarksClick,
  onProfileClick,
  onToggleTheme,
  theme,
  activityCount,
  bookmarkCount,
}) {
  const labels = {
    overview: "Overview", opportunities: "Opportunities", map: "Map",
    pipeline: "Pipeline", partners: "Partner Finder", profile: "Company Profile",
  };

  return (
    <header className="topbar">
      <div className="crumbs">
        <span>SuSu Funding</span>
        <span className="sep">/</span>
        <span className="cur">{labels[active] || "Overview"}</span>
      </div>
      <label className="search">
        <Icon d={Icons.search} size={14} />
        <input
          ref={searchRef}
          value={query}
          onChange={e => setQuery(e.target.value)}
          placeholder="Search funders, programs, partners..."
        />
        <span className="kbd">⌘K</span>
      </label>
      <div className="topbar-actions">
        <button className="icon-btn" title="Activity" aria-label="Activity" onClick={onActivityClick}>
          <Icon d={Icons.bell} size={15} />
          {activityCount > 0 && <span className="notif-dot"></span>}
        </button>
        <button className="icon-btn" title="Bookmarks" aria-label="Bookmarks" onClick={onBookmarksClick}>
          <Icon d={Icons.bookmark} size={15} />
          {bookmarkCount > 0 && <span className="count-dot">{bookmarkCount}</span>}
        </button>
        <button
          className="icon-btn"
          title={theme === "dark" ? "Switch to light theme" : "Switch to dark theme"}
          aria-label="Toggle theme"
          onClick={onToggleTheme}
        >
          <Icon d={Icons.spark} size={15} />
        </button>
        <button className="user-chip" onClick={onProfileClick}>
          <div className="avatar">TG</div>
          <div className="stack gap-2">
            <div className="user-name">Tewodros G.</div>
            <div className="user-org">SuSu Technology</div>
          </div>
        </button>
      </div>
    </header>
  );
}

function App() {
  const defaultTweaks = loadStored(STORAGE.tweaks, window.TWEAK_DEFAULTS);
  const [t, setTweak] = useTweaks(defaultTweaks);
  const [route, setRoute] = useState(routeFromHash);
  const [filterRegion, setFilterRegion] = useState("all");
  const [opp, setOpp] = useState(null);
  const [query, setQuery] = useState("");
  const [toast, setToast] = useState(null);
  const [activePanel, setActivePanel] = useState(null);
  const [opportunities] = useState(() => withLiveDeadlines(window.OPPORTUNITIES));
  const [pipeline, setPipeline] = useState(() => loadStored(STORAGE.pipeline, window.PIPELINE));
  const [activity, setActivity] = useState(() => loadStored(STORAGE.activity, window.ACTIVITY));
  const [bookmarks, setBookmarks] = useState(() => loadStored(STORAGE.bookmarks, []));
  const [introRequests, setIntroRequests] = useState(() => loadStored(STORAGE.intros, []));
  const searchRef = useRef(null);
  const toastTimer = useRef(null);
  const defaultActivity = useRef(window.ACTIVITY);

  window.OPPORTUNITIES = opportunities;
  window.PIPELINE = pipeline;
  window.ACTIVITY = activity;
  window.PARTNERS = window.PARTNERS || [];

  useEffect(() => saveStored(STORAGE.tweaks, t), [t]);
  useEffect(() => saveStored(STORAGE.pipeline, pipeline), [pipeline]);
  useEffect(() => saveStored(STORAGE.activity, activity), [activity]);
  useEffect(() => saveStored(STORAGE.bookmarks, bookmarks), [bookmarks]);
  useEffect(() => saveStored(STORAGE.intros, introRequests), [introRequests]);

  useEffect(() => {
    document.documentElement.setAttribute("data-theme", t.theme);
    document.documentElement.style.setProperty("--accent", t.accent);
    const dens = t.density;
    document.documentElement.style.setProperty("--sidebar-w", dens === "compact" ? "212px" : dens === "comfy" ? "260px" : "240px");
    document.documentElement.style.setProperty("--topbar-h", dens === "compact" ? "56px" : dens === "comfy" ? "72px" : "64px");
  }, [t.theme, t.accent, t.density]);

  useEffect(() => {
    const onHash = () => setRoute(routeFromHash());
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);

  useEffect(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault();
        searchRef.current?.focus();
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);

  const showToast = (text, tone = "success") => {
    window.clearTimeout(toastTimer.current);
    setToast({ text, tone });
    toastTimer.current = window.setTimeout(() => setToast(null), 2800);
  };

  const addActivity = (text, tag = "system") => {
    setActivity(prev => [{ ts: "now", text, tag }, ...prev].slice(0, 14));
  };

  const go = (id) => {
    if (!ROUTES.includes(id)) return;
    setRoute(id);
    window.history.replaceState(null, "", `#${id}`);
    window.scrollTo(0, 0);
    setActivePanel(null);
  };

  const openOpp = (o) => {
    setOpp(o);
    setActivePanel(null);
  };
  const closeOpp = () => setOpp(null);

  const addOpportunityToPipeline = (targetOpp, stage = "identified") => {
    if (!targetOpp) return false;
    if (pipeline.some(p => p.oppId === targetOpp.id)) {
      showToast(`"${targetOpp.name}" is already in the pipeline`, "info");
      return false;
    }
    const next = {
      id: `pipe-${Date.now()}`,
      oppId: targetOpp.id,
      stage,
      updated: "today",
      owner: "Tewodros",
    };
    setPipeline(prev => [next, ...prev]);
    addActivity(`Added ${targetOpp.name} to the pipeline`, "pipeline");
    showToast(`Added "${targetOpp.name}" to pipeline`);
    return true;
  };

  const addBestAvailable = () => {
    const existing = new Set(pipeline.map(p => p.oppId));
    const next = opportunities
      .filter(o => o.status === "open" && !existing.has(o.id))
      .sort((a, b) => b.match - a.match)[0];
    if (next) addOpportunityToPipeline(next);
    else showToast("Every open opportunity is already in the pipeline", "info");
  };

  const onAdd = () => {
    const added = addOpportunityToPipeline(opp);
    if (added) setOpp(null);
  };

  const movePipeline = (pipelineId, stage) => {
    const item = pipeline.find(p => p.id === pipelineId);
    if (!item || item.stage === stage) return;
    const target = opportunities.find(o => o.id === item.oppId);
    setPipeline(prev => prev.map(p => p.id === pipelineId ? { ...p, stage, updated: "today" } : p));
    addActivity(`Moved ${target?.name || "an opportunity"} to ${stage}`, "pipeline");
    showToast("Pipeline stage updated");
  };

  const requestIntro = (partner) => {
    if (!partner) return;
    if (introRequests.includes(partner.id)) {
      showToast(`Intro already requested for ${partner.name}`, "info");
      return;
    }
    setIntroRequests(prev => [...prev, partner.id]);
    addActivity(`Partner intro requested with ${partner.name}`, "partner");
    showToast(`Intro requested with ${partner.name}`);
  };

  const toggleBookmark = (type, id, label) => {
    const key = `${type}:${id}`;
    const exists = bookmarks.includes(key);
    setBookmarks(prev => exists ? prev.filter(x => x !== key) : [...prev, key]);
    showToast(exists ? `Removed ${label} from bookmarks` : `Saved ${label} to bookmarks`, exists ? "info" : "success");
  };

  const bookmarkItems = useMemo(() => bookmarks.map(key => {
    const [type, id] = key.split(":");
    if (type === "opportunity") {
      const item = opportunities.find(o => o.id === id);
      return item ? { key, type, label: item.name, meta: item.source, item } : null;
    }
    const partner = window.PARTNERS.find(p => p.id === id);
    return partner ? { key, type, label: partner.name, meta: `${partner.country} · ${partner.type}`, item: partner } : null;
  }).filter(Boolean), [bookmarks, opportunities]);

  const filteredQ = query.trim().toLowerCase();
  const searchResults = filteredQ ? [
    ...opportunities.filter(o =>
      o.name.toLowerCase().includes(filteredQ) ||
      o.source.toLowerCase().includes(filteredQ) ||
      o.sectors.some(s => s.toLowerCase().includes(filteredQ))
    ).map(item => ({ type: "opportunity", item })),
    ...window.PARTNERS.filter(p =>
      p.name.toLowerCase().includes(filteredQ) ||
      p.country.toLowerCase().includes(filteredQ) ||
      p.expertise.some(s => s.toLowerCase().includes(filteredQ))
    ).map(item => ({ type: "partner", item })),
  ].slice(0, 8) : [];

  const counts = {
    opportunities: opportunities.filter(o => o.status === "open").length,
    pipeline: pipeline.length,
    partners: window.PARTNERS.length,
  };

  const oppBookmarked = opp ? bookmarks.includes(`opportunity:${opp.id}`) : false;
  const oppInPipeline = opp ? pipeline.some(p => p.oppId === opp.id) : false;

  return (
    <div className="app" data-density={t.density}>
      <Sidebar active={route} go={go} counts={counts} />
      <main className="main">
        <Topbar
          active={route}
          setQuery={setQuery}
          query={query}
          searchRef={searchRef}
          onActivityClick={() => setActivePanel(activePanel === "activity" ? null : "activity")}
          onBookmarksClick={() => setActivePanel(activePanel === "bookmarks" ? null : "bookmarks")}
          onProfileClick={() => go("profile")}
          onToggleTheme={() => setTweak("theme", t.theme === "dark" ? "light" : "dark")}
          theme={t.theme}
          activityCount={activity.length}
          bookmarkCount={bookmarks.length}
        />

        {activePanel === "activity" && (
          <div className="app-popover">
            <div className="popover-head">
              <span>Recent activity</span>
              <button className="btn btn-sm btn-ghost" onClick={() => { setActivity(defaultActivity.current); showToast("Activity reset", "info"); }}>Reset</button>
            </div>
            <div className="stack gap-10">
              {activity.slice(0, 8).map((a, i) => (
                <div key={`${a.text}-${i}`} className="popover-row">
                  <span className="mono mute">{a.ts}</span>
                  <span>{a.text}</span>
                </div>
              ))}
            </div>
          </div>
        )}

        {activePanel === "bookmarks" && (
          <div className="app-popover">
            <div className="popover-head">
              <span>Bookmarks</span>
              {bookmarks.length > 0 && <button className="btn btn-sm btn-ghost" onClick={() => setBookmarks([])}>Clear</button>}
            </div>
            <div className="stack gap-8">
              {bookmarkItems.map(({ key, type, label, meta, item }) => (
                <button
                  key={key}
                  className="popover-link"
                  onClick={() => {
                    if (type === "opportunity") openOpp(item);
                    else go("partners");
                  }}
                >
                  <span className="stack gap-2">
                    <span>{label}</span>
                    <span className="dim">{meta}</span>
                  </span>
                  <Icon d={type === "opportunity" ? Icons.briefcase : Icons.users} size={13} />
                </button>
              ))}
              {bookmarkItems.length === 0 && <div className="empty-note">No saved items yet.</div>}
            </div>
          </div>
        )}

        {searchResults.length > 0 && (
          <div className="search-results">
            {searchResults.map(({ type, item }) => (
              <button
                key={`${type}-${item.id}`}
                className="search-result"
                onClick={() => {
                  if (type === "opportunity") openOpp(item);
                  else go("partners");
                  setQuery("");
                }}
              >
                <span style={{fontSize:18}}>{item.flag || "•"}</span>
                <span className="stack gap-2" style={{flex:1, minWidth:0}}>
                  <span style={{fontSize:13, fontWeight:500, overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap"}}>{item.name}</span>
                  <span className="dim" style={{fontSize:11}}>
                    {type === "opportunity" ? `${item.source} · ${fmtAmount(item.amountMin, item.amountMax, item.currency)}` : `${item.country} · ${item.type}`}
                  </span>
                </span>
                <Pill tone={type === "opportunity" ? regionTone(item.region) : "info"}>{type === "opportunity" ? item.region : "Partner"}</Pill>
              </button>
            ))}
          </div>
        )}

        <div className="content">
          {route === "overview"      && <OverviewView go={go} openOpp={openOpp} />}
          {route === "opportunities" && <OpportunitiesView openOpp={openOpp} filterRegion={filterRegion} setFilterRegion={setFilterRegion} />}
          {route === "map"           && <MapView openOpp={openOpp} />}
          {route === "pipeline"      && <PipelineView openOpp={openOpp} pipeline={pipeline} movePipeline={movePipeline} addBestAvailable={addBestAvailable} />}
          {route === "partners"      && <PartnersView onRequestIntro={requestIntro} introRequests={introRequests} bookmarks={bookmarks} onToggleBookmark={toggleBookmark} />}
          {route === "profile"       && <ProfileView onExportProfile={() => showToast("Eligibility brief exported", "success")} />}
        </div>
      </main>

      <Drawer open={!!opp} onClose={closeOpp}>
        <OppDetail
          opp={opp}
          onClose={closeOpp}
          onAddToPipeline={onAdd}
          inPipeline={oppInPipeline}
          bookmarked={oppBookmarked}
          onToggleBookmark={() => opp && toggleBookmark("opportunity", opp.id, opp.name)}
        />
      </Drawer>

      {toast && (
        <div className="toast" data-tone={toast.tone}>
          <div className="toast-icon">
            <Icon d={toast.tone === "info" ? Icons.bookmark : Icons.check} size={14}/>
          </div>
          <div style={{fontSize:13}}>{toast.text}</div>
        </div>
      )}

      <TweaksPanel>
        <TweakSection label="Appearance" />
        <TweakRadio label="Theme" value={t.theme} options={["dark", "light"]} onChange={(v) => setTweak("theme", v)} />
        <TweakColor label="Accent" value={t.accent} options={["#f5b800", "#34d399", "#60a5fa", "#a78bfa", "#f87171"]} onChange={(v) => setTweak("accent", v)} />
        <TweakSection label="Layout" />
        <TweakRadio label="Density" value={t.density} options={["compact", "regular", "comfy"]} onChange={(v) => setTweak("density", v)} />
      </TweaksPanel>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
