/* StrataSnap prototype — root. Babel/JSX. In-memory store + routing + frame. */
const { useState, useEffect } = React;

// Council-selectable app accents stay constrained to the StrataSnap theme presets.
const ACCENTS = (window.SS && window.SS.APP_THEMES) || [
  { key: 'blue', acc: '#1E50C8', strong: '#1A45AE', text: '#1A45AE', tint: '#EAF0FC', border: '#C9D8F6' },
];
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "accent": "#1E50C8" }/*EDITMODE-END*/;
function applyAccent(value) {
  const themes = (window.SS && window.SS.APP_THEMES) || ACCENTS;
  const a = themes.find((x) => x.key === value || x.acc === value) || themes[0];
  const r = document.documentElement.style;
  r.setProperty('--acc', a.acc); r.setProperty('--acc-strong', a.strong);
  r.setProperty('--acc-text', a.text); r.setProperty('--acc-tint', a.tint);
  r.setProperty('--acc-tint-border', a.border);
}

function App() {
  const SS = window.SS;
  const Store = window.SSStore;
  const Api = window.SSPilotApi;
  const params = new URLSearchParams(window.location.search || '');
  const apiEnabled = !!(Api && Api.enabled());
  const directQrCode = params.get('qr') || params.get('scan') || '';
  const directLocationId = params.get('loc') || '';
  const directOnboarding = params.get('onboarding') === '1' || params.get('demo') === 'onboarding' || params.get('view') === 'setup';
  useEffect(() => {
    if (!apiEnabled && directOnboarding && !Store.getSession('council').authed) {
      Store.signIn({ role: 'council', email: 'dana.lee@harbourview.ca' });
    }
  }, []);
  const initialCouncilSession = apiEnabled ? Api.getSession('council') : Store.getSession('council');
  const [tickets, setTickets] = useState(() => Store.loadTickets(() => SS.seed()));
  const [setup, setSetup] = useState(() => Store.loadSetup(() => SS.setupSeed()));
  const [role, setRole] = useState(() => (directOnboarding || initialCouncilSession.authed) ? 'council' : 'reporter');

  // reporter routing
  const [rScreen, setRScreen] = useState(directQrCode || directLocationId ? 'scan' : 'home'); // home | scan | find | report | status
  const [scanLoc, setScanLoc] = useState(directLocationId || 'p2');
  const [token, setToken] = useState(null);
  const [reportKey, setReportKey] = useState(1);

  // council routing
  const [cScreen, setCScreen] = useState(directOnboarding ? 'setup' : 'dashboard');   // dashboard | queue | setup | map | ticket | new | posters | poster | updates | settings
  const [openId, setOpenId] = useState(null);
  const [openLoc, setOpenLoc] = useState(null);
  const [authed, setAuthed] = useState(() => directOnboarding || initialCouncilSession.authed);
  const [statusTicket, setStatusTicket] = useState(null);

  const [toast, setToast] = useState(null);
  useEffect(() => { if (!toast) return; const t = setTimeout(() => setToast(null), 2600); return () => clearTimeout(t); }, [toast]);
  useEffect(() => { if (!apiEnabled) Store.saveTickets(tickets); }, [tickets]);
  useEffect(() => { if (!apiEnabled) Store.saveSetup(setup); }, [setup]);
  useEffect(() => {
    if (!apiEnabled || !authed) return;
    let cancelled = false;
    Api.hydrate().then((data) => {
      if (cancelled) return;
      setSetup(data.setup);
      setTickets(data.tickets);
      setToast('Connected to pilot API');
    }).catch((err) => setToast('Pilot API unavailable: ' + err.message));
    return () => { cancelled = true; };
  }, [apiEnabled, authed]);
  useEffect(() => {
    if (!apiEnabled || authed || role !== 'reporter' || !Api.publicSetup) return;
    let cancelled = false;
    Api.publicSetup().then((data) => {
      if (cancelled) return;
      setSetup(data.setup);
    }).catch((err) => setToast('Building setup unavailable: ' + err.message));
    return () => { cancelled = true; };
  }, [apiEnabled, authed, role]);
  useEffect(() => {
    if (!apiEnabled || authed || !Api.completeSupabaseRedirect) return;
    let cancelled = false;
    Api.completeSupabaseRedirect().then((session) => {
      if (cancelled || !session) return;
      setAuthed(true);
      setRole('council');
      setToast('Signed in with Supabase');
    }).catch((err) => setToast('Supabase sign-in failed: ' + err.message));
    return () => { cancelled = true; };
  }, [apiEnabled, authed]);

  const [tw, setTweak] = useTweaks(TWEAK_DEFAULTS);
  useEffect(() => { applyAccent(setup.appTheme || tw.accent); }, [setup.appTheme, tw.accent]);
  useEffect(() => {
    if (!(directQrCode || directLocationId)) return;
    const byQr = directQrCode ? SS.setupLocationByQr(setup, directQrCode) : null;
    const byId = directLocationId ? SS.setupLocationById(setup, directLocationId) : null;
    const target = byQr || byId;
    if (target) setScanLoc(target.id);
    setRole('reporter');
    setRScreen('scan');
  }, [setup, directQrCode, directLocationId]);

  // ── store mutations ──
  const patchTicket = (id, fn) => setTickets((ts) => ts.map((t) => (t.id === id ? fn(t) : t)));
  const addEvents = (id, evs) => setTickets((ts) => ts.map((t) => (t.id === id ? { ...t, timeline: [...t.timeline, ...evs] } : t)));
  const patchSetup = (patch) => setSetup((s) => {
    const next = SS.normalizeSetup(typeof patch === 'function' ? patch(s) : { ...s, ...patch });
    if (apiEnabled) {
      Api.saveSetup(next).catch((err) => setToast('Setup saved locally; API sync failed: ' + err.message));
    }
    return next;
  });
  const nextId = () => {
    const nums = tickets.map((t) => parseInt((t.id.split('-')[1] || '0'), 10)).filter((n) => !isNaN(n));
    return 'SS-' + ((nums.length ? Math.max(...nums) : 1042) + 1);
  };
  const newToken = () => Math.random().toString(36).slice(2, 8);
  const cap = (s) => (s ? s.charAt(0).toUpperCase() + s.slice(1) : s);

  function createTicket(draft) {
    const note = (draft.note || '').trim();
    const words = note ? note.split(/\s+/) : [];
    let summary = note ? words.slice(0, 8).join(' ') + (words.length > 8 ? '…' : '') : SS.catLabel(draft.category);
    summary = cap(summary);
    const media = [];
    if ((draft.photos || []).length) media.push((draft.photos || []).length + ' photo' + ((draft.photos || []).length === 1 ? '' : 's'));
    if ((draft.voiceNotes || []).length) media.push((draft.voiceNotes || []).length + ' voice note' + ((draft.voiceNotes || []).length === 1 ? '' : 's'));
    const mediaNote = media.length ? ' Included ' + media.join(' and ') + '.' : '';
    const t = {
      id: nextId(), token: newToken(), locationId: draft.locationId, locationName: draft.locationName,
      category: draft.category, summary, status: 'New', priority: 'Normal', responsibility: null, assignee: null,
      source: 'qr', reporterName: draft.name || 'Resident', reporterEmail: draft.email || '', reporterPhone: draft.phone || '',
      unit: draft.unit || '', photos: draft.photos || [], voiceNotes: draft.voiceNotes || [], createdAt: SS.NOW.toISOString(), nextStep: 'Needs triage',
      timeline: [{ id: SS.uid('e'), at: SS.NOW.toISOString(), kind: 'submitted', body: 'Reported via QR at ' + draft.locationName + '.' + mediaNote, author: draft.name || 'Resident' }],
    };
    setTickets((ts) => [t, ...ts]);
    if (apiEnabled) {
      Api.createTicket({ ...draft, id: t.id, token: t.token }).then(() => {
        if (!authed) return null;
        return Api.hydrate().then((data) => {
          setSetup(data.setup);
          setTickets(data.tickets);
        });
      }).catch((err) => setToast('Saved locally; API write failed: ' + err.message));
    }
    return t;
  }

  function createCouncilTicket(draft) {
    const id = nextId();
    const t = {
      id, token: newToken(), locationId: draft.locationId, locationName: draft.locationName,
      category: draft.category, summary: cap(draft.summary.trim()), status: 'New', priority: 'Normal',
      responsibility: null, assignee: null, source: draft.source,
      reporterName: draft.name || 'Logged by council', reporterEmail: draft.email || '', reporterPhone: draft.phone || '',
      unit: draft.unit || '', photos: [], voiceNotes: [], createdAt: SS.NOW.toISOString(), nextStep: 'Needs triage',
      timeline: [{ id: SS.uid('e'), at: SS.NOW.toISOString(), kind: 'submitted', body: 'Logged by council (' + draft.source + ').', author: 'Dana Lee' }],
    };
    setTickets((ts) => [t, ...ts]);
    if (apiEnabled && authed) {
      Api.createTicket({ ...draft, id: t.id, token: t.token, note: draft.summary, reporterName: draft.name, reporterEmail: draft.email }).then(() => Api.hydrate()).then((data) => {
        setSetup(data.setup);
        setTickets(data.tickets);
      }).catch((err) => setToast('Saved locally; API write failed: ' + err.message));
    }
    setCScreen('queue'); setToast(id + ' added to the issue inbox');
  }

  const switchRole = (r) => { setRole(r); if (r === 'reporter') setRScreen('home'); else setCScreen('dashboard'); setToast(null); };
  const openStatus = (t) => {
    setStatusTicket(t);
    setToken(t.token);
    setRScreen('status');
  };

  let body;
  if (role === 'reporter') {
    if (rScreen === 'home') {
      body = <ResidentHome tickets={tickets}
        onReport={() => setRScreen('scan')}
        onMap={() => setRScreen('scan')}
        onMyIssues={() => setRScreen('find')}
        onOpenTicket={(id) => { const t = tickets.find((x) => x.id === id); if (t) { setToken(t.token); setRScreen('status'); } }} />;
    } else if (rScreen === 'scan') {
      body = <ScanLanding setup={setup} locationId={scanLoc} onScanned={(id) => { setScanLoc(id); setReportKey((k) => k + 1); setRScreen('report'); }} onFind={() => setRScreen('find')} />;
    } else if (rScreen === 'find') {
      body = <FindReport tickets={tickets} onBack={() => setRScreen('home')}
        lookupReport={apiEnabled ? (code) => Api.getStatus(code) : null}
        onFound={(tok, foundTicket) => {
          if (foundTicket) openStatus(foundTicket);
          else { setStatusTicket(null); setToken(tok); setRScreen('status'); }
        }} />;
    } else if (rScreen === 'report') {
      body = <ReportFlow key={reportKey} setup={setup} locationId={scanLoc} createTicket={createTicket}
        onViewStatus={(tok) => { setToken(tok); setRScreen('status'); }}
        onExit={() => { setReportKey((k) => k + 1); setRScreen('home'); }} />;
    } else {
      const t = (statusTicket && statusTicket.token === token) ? statusTicket : tickets.find((x) => x.token === token);
      body = <StatusPage ticket={t} expired={!t || t.status === 'Closed'} onExit={() => { setReportKey((k) => k + 1); setRScreen('home'); }} />;
    }
  } else {
    const go = (s) => { setCScreen(s); setToast(null); };
    if (!authed) {
      body = <CouncilLogin onAuthed={(email) => {
        if (apiEnabled) {
          Api.signIn(email || 'dana.lee@harbourview.ca').then((result) => {
            if (result && result.pending) {
              setToast('Supabase sign-in link sent');
              return;
            }
            setAuthed(true); setToast('Signed in with pilot API');
          }).catch((err) => setToast('Pilot API sign-in failed: ' + err.message));
        } else {
          Store.signIn({ role: 'council', email }); setAuthed(true);
        }
      }} />;
    } else if (cScreen === 'dashboard') {
      body = <CouncilDashboard tickets={tickets} setup={setup} toast={toast} go={go}
        onOpen={(id) => { setOpenId(id); setCScreen('ticket'); setToast(null); }} />;
    } else if (cScreen === 'queue') {
      body = <Queue tickets={tickets} toast={toast} go={go}
        onOpen={(id) => { setOpenId(id); setCScreen('ticket'); setToast(null); }}
        onNew={() => { setCScreen('new'); setToast(null); }} />;
    } else if (cScreen === 'setup') {
      body = <BuildingSetupMobile setup={setup} patchSetup={patchSetup} toast={toast} setToast={setToast} go={go} startAtFirst={directOnboarding} />;
    } else if (cScreen === 'map') {
      body = <BuildingMapMobile tickets={tickets} go={go}
        onOpen={(id) => { setOpenId(id); setCScreen('ticket'); setToast(null); }} />;
    } else if (cScreen === 'settings') {
      body = <CouncilSettings setup={setup} go={go} onBack={() => { setCScreen('dashboard'); setToast(null); }}
        onSignOut={() => { if (apiEnabled) Api.signOut(); else Store.signOut(); setAuthed(false); setCScreen('dashboard'); }} />;
    } else if (cScreen === 'updates') {
      body = <Updates tickets={tickets} go={go}
        onOpen={(id) => { setOpenId(id); setCScreen('ticket'); setToast(null); }} />;
    } else if (cScreen === 'ticket') {
      body = <TicketDetail ticket={tickets.find((t) => t.id === openId)} toast={toast} setToast={setToast} go={go}
        patchTicket={patchTicket} addEvents={addEvents}
        pilotApi={apiEnabled ? Api : null}
        refreshFromApi={() => Api.hydrate().then((data) => { setSetup(data.setup); setTickets(data.tickets); })}
        onBack={() => { setCScreen('queue'); setToast(null); }} />;
    } else if (cScreen === 'posters') {
      body = <Posters setup={setup} go={go} onBack={() => { setCScreen('dashboard'); setToast(null); }} onOpen={(id) => { setOpenLoc(id); setCScreen('poster'); }} />;
    } else if (cScreen === 'poster') {
      body = <PosterDetail setup={setup} locationId={openLoc} toast={toast} setToast={setToast} onBack={() => { setCScreen('posters'); }} />;
    } else {
      body = <NewTicket onBack={() => { setCScreen('queue'); setToast(null); }} onCreate={createCouncilTicket} />;
    }
  }

  return (
    <div className="stage">
      <div className="role-switch">
        <button className={role === 'reporter' ? 'on' : ''} onClick={() => switchRole('reporter')}>Resident</button>
        <button className={role === 'council' ? 'on' : ''} onClick={() => switchRole('council')}>Council</button>
      </div>
      <div className="device">{body}</div>
      <div style={{ color: 'rgba(255,255,255,.4)', fontSize: 12.5, fontFamily: 'var(--font-mono)', letterSpacing: '.04em' }}>
        StrataSnap prototype · {role === 'reporter' ? 'resident report flow' : 'council triage'} · {apiEnabled ? 'pilot API' : 'dummy data'}
      </div>
      <TweaksPanel>
        <TweakSection label="Design system" />
        <div style={{ fontSize: 13, color: '#9a948a', padding: '2px 2px 0', lineHeight: 1.5 }}>
          StrataSnap runs on its own design system: council-selected accent presets, a cool-slate neutral ramp, five distinct status colours, and Plus Jakarta Sans. Theme presets stay constrained so buttons, cards, and resident views remain consistent.
        </div>
      </TweaksPanel>
    </div>
  );
}

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