// Bylt Capital CRM — sign-in, app shell, routing.

function Login({ onSignedIn }) {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [showPw, setShowPw] = useState(false);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState("");

  const submit = async (e) => {
    e.preventDefault();
    if (!email.trim() || !password) return setError("Enter your email and password.");
    setBusy(true); setError("");
    try { await API.login(email.trim(), password); onSignedIn(await API.me()); }
    catch (err) {
      setError(err.status === 401 ? (err.message === "Account disabled" ? "This account has been disabled. Ask an Admin to turn it back on." : "That email and password don't match.") : err.message);
      setBusy(false);
    }
  };

  return (
    <div className="login">
      <div className="login-brand">
        <span className="monogram" aria-hidden="true">b</span>
        <Brand size="lg" />
        <div className="pitch" style={{ position: "relative" }}>
          <h1>Every deal and every lender offer, in one file.</h1>
          <p>Track submissions, offers, documents and repayment from the first call to funding.</p>
        </div>
        <div className="foot">Staff access only. Sessions end after 8 hours without activity.</div>
      </div>
      <div className="login-form-side">
        <form className="login-form" onSubmit={submit} noValidate>
          <div className="label">Sign in</div>
          <h2>Welcome back.</h2>
          <p className="sub">Use your Bylt Capital email and password.</p>
          {error ? <div className="banner" role="alert" style={{ marginBottom: 16 }}>{error}</div> : null}
          <label className="field">
            <span className="label">Email</span>
            <input className="input" type="email" autoComplete="username" autoFocus value={email} onChange={e => setEmail(e.target.value)} />
          </label>
          <label className="field">
            <span className="label">Password</span>
            <span style={{ position: "relative", display: "block" }}>
              <input className="input" style={{ paddingRight: 64 }} type={showPw ? "text" : "password"} autoComplete="current-password" value={password} onChange={e => setPassword(e.target.value)} />
              <button type="button" className="link-btn" style={{ position: "absolute", right: 12, top: 12 }} onClick={() => setShowPw(!showPw)} aria-pressed={showPw}>{showPw ? "Hide" : "Show"}</button>
            </span>
          </label>
          <button className="btn btn-primary btn-lg btn-block" type="submit" disabled={busy}>{busy ? "Signing in…" : "Sign in"}</button>
          <div className="foot">Forgot your password? Ask an Admin to set a new one.</div>
        </form>
      </div>
    </div>
  );
}

// ── More: your account, plus the Admin sections on phones ──────────────────
function MorePage({ user, isAdmin, signOut }) {
  const may = user.can || {};
  const office = may.commissions === "all";
  const rows = (may.deals !== false ? [["map", "Map", "Where your clients, deals and leads are, and who's nearby to refer"]] : []).concat(may.deals ? [["lenders", "Lenders", isAdmin ? "Your lender list: contacts, renaming and merging" : "Who to send files to at each lender"]] : [])
    .concat(!may.commissions ? [] : [["commissions", office ? "Commissions" : "My commissions", office ? "What lenders owe, what the team is owed, clawbacks, and who funded what" : "Deals credited to you and what you have been paid"]])
    .concat(may.settings ? [
      ["team", "Team", "Who can sign in, their payout rates and overrides"],
      ["partners", "Partners", "Brokers who send you deals, and their access keys"],
      ["settings", "Settings", "Alerts and connected services"],
    ] : []);
  return (
    <main className="workspace single">
      <div className="page more-page">
        <div className="card account">
          <Avatar name={user.name || user.email} size="lg" />
          <div style={{ minWidth: 0 }}>
            <div className="serif" style={{ fontSize: 22, fontWeight: 500, lineHeight: 1.15 }}>{user.name || "Admin"}</div>
            <div className="dim" style={{ fontSize: 13, overflowWrap: "anywhere" }}>{user.email}</div>
            <div style={{ marginTop: 6 }}><span className="pill plain">{user.role}</span></div>
          </div>
        </div>
        {rows.length ? (
          <div className="card card-flush">
            {rows.map(([id, label, hint]) => (
              <button key={id} className="row more-row" onClick={() => go(id)}>
                <span className="grow"><span className="title">{label}</span><span className="line" style={{ display: "block" }}>{hint}</span></span>
                <span className="muted" style={{ alignSelf: "center" }}><Icon name="chev" /></span>
              </button>
            ))}
          </div>
        ) : null}
        <button className="btn btn-lg btn-block" onClick={signOut}>Sign out</button>
      </div>
    </main>
  );
}

// ── Routing: #/home, #/deals/<id>, #/leads, #/clients, #/lenders, #/commissions, #/team, #/partners, #/settings
function parseRoute() {
  // Anything after "?" (e.g. #/settings/constant-contact?cc=connected) is for the page to read, not part of the route.
  const parts = location.hash.replace(/^#\/?/, "").split("?")[0].split("/").filter(Boolean);
  let id = null;
  if (parts[1]) { try { id = decodeURIComponent(parts[1]); } catch { id = parts[1]; } }
  return { page: parts[0] || "home", id };
}
const go = (page, id, replace) => { const h = "#/" + page + (id ? "/" + encodeURIComponent(id) : ""); if (replace) { history.replaceState(null, "", h); window.dispatchEvent(new Event("hashchange")); } else location.hash = h; };

function App() {
  const [user, setUser] = useState(undefined);           // undefined = checking, null = signed out
  // The office's phone number, and whether texts, emails and statement reading are set up.
  const [office, setOffice] = useState({ phone: "", sms: false, email: false, statements: false });
  const signedIn = (r) => { if (r && r.office) setOffice(r.office); setUser(r ? r.user : null); };
  const [route, setRoute] = useState(parseRoute());
  const [deals, setDeals] = useState([]);
  const [dealsLoading, setDealsLoading] = useState(true);
  const [clients, setClients] = useState([]);
  const [team, setTeam] = useState([]);
  const [lenders, setLenders] = useState([]);
  const [loadError, setLoadError] = useState("");
  const [toastMsg, setToastMsg] = useState(null);
  const [dialog, setDialog] = useState(null);
  const toastTimer = useRef(null);
  const [updatesOpen, setUpdatesOpen] = useState(false);
  const home = useHome(user, route.page === "home" || updatesOpen);

  const toast = useCallback((text, bad) => {
    clearTimeout(toastTimer.current);
    setToastMsg({ text, bad: !!bad });
    toastTimer.current = setTimeout(() => setToastMsg(null), bad ? 6000 : 2600);
  }, []);
  const confirm = useCallback((opts) => setDialog(opts), []);

  useEffect(() => {
    API.me().then(signedIn).catch(() => setUser(null));
    const onHash = () => setRoute(parseRoute());
    const onOut = () => setUser(null);
    window.addEventListener("hashchange", onHash);
    window.addEventListener("ef:signed-out", onOut);
    return () => { window.removeEventListener("hashchange", onHash); window.removeEventListener("ef:signed-out", onOut); };
  }, []);

  const refreshDeals = useCallback(async () => {
    try { setDeals(await API.deals()); setLoadError(""); } catch (err) { if (err.status !== 401) setLoadError(err.message); }
    setDealsLoading(false);
  }, []);
  const refreshClients = useCallback(async () => { try { setClients(await API.clients()); } catch (e) { /* shown where it matters */ } }, []);
  const refreshTeam = useCallback(async () => { try { setTeam(await API.team()); } catch (e) { /* optional */ } }, []);
  const refreshLenders = useCallback(async () => { try { setLenders(await API.lenders()); } catch (e) { /* optional */ } }, []);

  useEffect(() => {
    if (!user) { setDeals([]); setClients([]); setTeam([]); setLenders([]); setDealsLoading(true); return; }
    const may = user.can || {};
    if (may.deals === false) return;                       // a Bookkeeper: commissions only
    refreshDeals(); refreshTeam(); refreshLenders();
    if (may.clients !== false) refreshClients();
  }, [user && (user.id || user.email)]);

  // Pick up deals added or changed elsewhere when the window comes back into view.
  useEffect(() => {
    if (!user) return;
    const onShow = () => { if (document.visibilityState === "visible" && (user.can || {}).deals !== false) { refreshDeals(); refreshLenders(); } };
    document.addEventListener("visibilitychange", onShow);
    return () => document.removeEventListener("visibilitychange", onShow);
  }, [user && (user.id || user.email)]);

  // On wide screens, open the first deal instead of showing an empty file.
  useEffect(() => {
    if (user && route.page === "deals" && !route.id && deals.length && window.matchMedia("(min-width: 901px)").matches) {
      history.replaceState(null, "", "#/deals/" + encodeURIComponent(deals[0].id));
      setRoute(parseRoute());
    }
  }, [user, route.page, route.id, deals.length]);

  // What this person may open (the server decides: GET /api/me sends `can`, see src/roles.js).
  const may = (user && user.can) || {};
  const homePage = may.deals === false ? "commissions" : "home";        // a Bookkeeper starts on Commissions
  // An address this person can't open (or a typo) goes to their first page.
  const allowed = ["more"].concat(may.deals !== false ? ["home", "deals", "map", "lenders"] : [], may.leads !== false ? ["leads"] : [], may.clients !== false ? ["clients"] : [],
    may.commissions ? ["commissions"] : [], may.settings ? ["team", "partners", "settings"] : [], may.import ? ["import"] : []);
  useEffect(() => {
    if (user && !allowed.includes(route.page)) { history.replaceState(null, "", "#/" + homePage); setRoute(parseRoute()); }
  }, [user, route.page]);

  if (user === undefined) return <div className="boot">Loading…</div>;
  if (!user) return <Login onSignedIn={(r) => { signedIn(r); if (!location.hash) go("home"); }} />;

  const isAdmin = !!may.manage;
  const pages = [
    { id: "home", label: "Home" }, { id: "deals", label: "Deals" }, { id: "leads", label: "Leads" }, { id: "clients", label: "Clients" }, { id: "map", label: "Map" }, { id: "lenders", label: "Lenders" },
    { id: "commissions", label: "Commissions" }, { id: "team", label: "Team" }, { id: "partners", label: "Partners" }, { id: "settings", label: "Settings" },
  ].filter(p => allowed.includes(p.id));
  const page = route.page === "more" || (route.page === "import" && may.import) || pages.some(p => p.id === route.page) ? route.page : homePage;
  // Phones: five tabs along the bottom. Lenders, Commissions, Team, Partners and Settings live under More.
  const adminPages = ["lenders", "commissions", "team", "partners", "settings"];
  const tabs = [["home", "Home", "home"], ["deals", "Deals", "deals"], ["leads", "Leads", "funnel"], ["clients", "Clients", "users"]].filter(t => allowed.includes(t[0]))
    .concat(may.deals === false && may.commissions ? [["commissions", "Commissions", "dollar"]] : [], [["more", "More", "menu"]]);
  const tab = tabs.some(t => t[0] === page) ? page : page === "more" || page === "map" || adminPages.includes(page) ? "more" : page === "import" ? "leads" : page;
  const unseen = home.data ? home.data.grok.filter(g => g.isNew).length + home.data.notices.filter(n => n.isNew).length : 0;
  const signOut = async () => { try { await API.logout(); } catch (e) { /* cookie is cleared either way */ } location.hash = ""; setUser(null); };
  // With all nine sections (an Admin) the bar is too long for a narrow window:
  // there, the ones under More fold into a More button and show as a second row.
  const fold = pages.length > 7;
  const navButtons = pages.map(p => <button key={p.id} className={fold && adminPages.includes(p.id) ? "sec" : undefined} aria-current={page === p.id || (page === "import" && p.id === "leads") ? "page" : undefined} onClick={() => go(p.id)}>{p.label}</button>)
    .concat(fold ? [<button key="more" className="more-btn" aria-current={tab === "more" ? "page" : undefined} onClick={() => go("more")}>More</button>] : []);
  const shared = { user, office, toast, confirm };

  return (
    <div className={`app${(page === "deals" || page === "clients") && route.id ? " in-file" : ""}`}>
      <header className="topbar">
        <Brand />
        <span className="brand-tag">CRM</span>
        <nav className="nav" aria-label="Sections">{navButtons}</nav>
        <span className="spacer" />
        {may.deals !== false ? <button className="bell" onClick={() => setUpdatesOpen(true)} aria-label={unseen ? `Updates, ${unseen} new` : "Updates"}>
          <Icon name="bell" size={17} />{unseen ? <span className="badge tnum">{unseen > 9 ? "9+" : unseen}</span> : null}
        </button> : null}
        <button className="userchip" onClick={() => go("more")} aria-label={`Your account: ${user.name || user.email}`}>
          <Avatar name={user.name || user.email} size="sm" />
          <span className="who"><b>{user.name || user.email}</b><span>{user.role}</span></span>
        </button>
        <button className="signout" onClick={signOut}>Sign out</button>
      </header>
      {(may.settings || may.manage) && adminPages.includes(page) ? (
        <nav className="subnav" aria-label="More sections">
          {pages.filter(p => adminPages.includes(p.id)).map(p => <button key={p.id} aria-current={page === p.id ? "page" : undefined} onClick={() => go(p.id)}>{p.label}</button>)}
        </nav>
      ) : null}

      {loadError && page === "deals" ? <div className="banner" role="alert" style={{ margin: 12 }}>Couldn't load deals: {loadError} <button className="link-btn" onClick={refreshDeals}>Try again</button></div> : null}

      <ErrorBoundary resetKey={page + "/" + (route.id || "")}>
      {page === "home" ? <HomeView {...shared} home={home} go={go} /> : null}
      {page === "deals" ? (
        <DealsView {...shared} deals={deals} setDeals={setDeals} loading={dealsLoading} selectedId={route.id} select={(id) => go("deals", id)}
          clients={clients} team={team} lenders={lenders} refreshClients={refreshClients} refreshLenders={refreshLenders} go={go} />
      ) : null}
      {page === "leads" ? <LeadsView {...shared} team={team} lenders={lenders} selectedId={route.id} select={(id) => go("leads", id)} onConverted={(d) => { setDeals(prev => [d, ...prev.filter(x => x.id !== d.id)]); refreshDeals(); go("deals", d.id); }} /> : null}
      {page === "import" ? <ImportView {...shared} selectedId={route.id} select={(id) => go("import", id)} go={go} /> : null}
      {page === "clients" ? <ClientsView {...shared} clients={clients} deals={deals} team={team} lenders={lenders} refreshClients={refreshClients} refreshDeals={refreshDeals} selectedId={route.id} select={(id, replace) => go("clients", id, replace)} go={go} /> : null}
      {page === "map" ? <MapView {...shared} focus={route.id} /> : null}
      {page === "lenders" ? <LendersView {...shared} lenders={lenders} refreshLenders={refreshLenders} /> : null}
      {page === "commissions" ? <CommissionsView {...shared} go={go} /> : null}
      {page === "team" ? <TeamView {...shared} me={user} onTeamChanged={refreshTeam} go={go} /> : null}
      {page === "partners" ? <PartnersView {...shared} /> : null}
      {page === "settings" ? <SettingsView {...shared} section={route.id} go={go} onOfficeChanged={() => API.me().then(r => r.office && setOffice(r.office)).catch(() => {})} /> : null}
      {page === "more" ? <MorePage user={user} isAdmin={isAdmin} signOut={signOut} /> : null}
      </ErrorBoundary>

      <nav className="tabbar" aria-label="Sections">
        {tabs.map(([id, label, icon]) => (
          <button key={id} aria-current={tab === id ? "page" : undefined} onClick={() => go(id)}><Icon name={icon} size={21} />{label}</button>
        ))}
      </nav>

      {updatesOpen ? <UpdatesSheet data={scopeHome(home.data, false, user)} go={go} onClose={() => setUpdatesOpen(false)} /> : null}
      {dialog ? <ConfirmDialog {...dialog} onCancel={() => setDialog(null)} onConfirm={async () => { await dialog.onConfirm(); setDialog(null); }} /> : null}
      {toastMsg ? <div className={`toast${toastMsg.bad ? " bad" : ""}`} role="status">{toastMsg.text}</div> : null}
    </div>
  );
}

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