// App.jsx — root, routing, sidebar, responsive layout
// (syncPushPrefsToIDB is defined in index.html before this script loads)
const I18N = {
  es: {
    home: 'Inicio', map: 'Mapa', report: 'Reportar', news: 'Novedades', profile: 'Perfil',
    frequency: 'Frecuencia', normalService: 'Normal', delays: 'Demoras', alert: 'Alerta',
    nextTrain: 'Próximo tren', endToEnd: 'punta a punta', allNormal: 'Todo funcionando con normalidad',
    linesWithIssues: 'líneas con novedades', liveUpdate: 'En vivo', openMap: 'Ver mapa', reportIncident: 'Reportar',
    nearYou: 'Cerca tuyo', status: 'Estado', schematic: 'Esquema', geographic: 'Mapa real', liveTrains: 'Trenes en vivo',
    whatHappened: '¿Qué está pasando?', whichLine: '¿Qué línea?', addDetails: 'Agregá detalles opcionales...',
    photo: 'Foto', pickStation: 'Elegir estación', sendReport: 'Enviar reporte', thanks: '¡Gracias!',
    reportSent: 'Tu reporte ayuda a otros pasajeros. Lo vamos a revisar en los próximos minutos.',
    backHome: 'Volver al inicio', assistant: 'Asistente', askMe: 'Preguntame algo...',
    settings: 'Ajustes', appearance: 'Apariencia', theme: 'Tema', language: 'Idioma',
    notifications: 'Notificaciones', data: 'Datos y privacidad', aboutApp: 'Acerca de',
    about: 'Acerca de', yourLocation: 'Tu ubicación',
  },
  en: {
    home: 'Home', map: 'Map', report: 'Report', news: 'News', profile: 'Profile',
    frequency: 'Frequency', normalService: 'Normal', delays: 'Delays', alert: 'Alert',
    nextTrain: 'Next train', endToEnd: 'end to end', allNormal: 'All lines running normally',
    linesWithIssues: 'lines with issues', liveUpdate: 'Live', openMap: 'Open map', reportIncident: 'Report',
    nearYou: 'Near you', status: 'Status', schematic: 'Schematic', geographic: 'Geographic', liveTrains: 'Live trains',
    whatHappened: "What's happening?", whichLine: 'Which line?', addDetails: 'Add optional details...',
    photo: 'Photo', pickStation: 'Pick station', sendReport: 'Send report', thanks: 'Thanks!',
    reportSent: "Your report helps other passengers. We'll review it in the next few minutes.",
    backHome: 'Back home', assistant: 'Assistant', askMe: 'Ask me something...',
    settings: 'Settings', appearance: 'Appearance', theme: 'Theme', language: 'Language',
    notifications: 'Notifications', data: 'Data & privacy', aboutApp: 'About',
    about: 'About', yourLocation: 'Your location',
  }
};

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "light",
  "lang": "es"
}/*EDITMODE-END*/;

// Breakpoint for sidebar / desktop layout
const DESKTOP_BP = 768;

function useIsDesktop() {
  const [wide, setWide] = React.useState(window.innerWidth >= DESKTOP_BP);
  React.useEffect(() => {
    const fn = () => setWide(window.innerWidth >= DESKTOP_BP);
    window.addEventListener('resize', fn);
    return () => window.removeEventListener('resize', fn);
  }, []);
  return wide;
}

function App() {
  const initial = (() => { try { return JSON.parse(localStorage.getItem('alsubte') || '{}'); } catch { return {}; } })();
  const [screen, setScreen] = React.useState(initial.screen || 'main');
  const [params, setParams] = React.useState(initial.params || {});
  const [theme, setTheme]   = React.useState(initial.theme || TWEAK_DEFAULTS.theme || 'auto');
  const [lang, setLang]     = React.useState(initial.lang  || TWEAK_DEFAULTS.lang);
  const [authed, setAuthed] = React.useState(false);
  const [pushPrefs, setPushPrefs] = React.useState(() => {
    try {
      const saved = JSON.parse(localStorage.getItem('alsubte-push-prefs') || 'null');
      if (saved && typeof saved === 'object') return { ...PUSH_DEFAULTS, ...saved, lines: { ...PUSH_DEFAULTS.lines, ...(saved.lines || {}) }, lineConfig: { ...PUSH_DEFAULTS.lineConfig, ...(saved.lineConfig || {}) } };
    } catch {}
    return PUSH_DEFAULTS;
  });
  const [tweaksOpen, setTweaksOpen] = React.useState(false);
  const isDesktop = useIsDesktop();

  // PWA install prompt — captured on beforeinstallprompt, shown after visiting a line detail
  const [installPrompt, setInstallPrompt] = React.useState(null);
  const [showInstallBanner, setShowInstallBanner] = React.useState(false);
  const hasVisitedLineDetail = React.useRef(false);
  React.useEffect(() => {
    const handler = (e) => { e.preventDefault(); setInstallPrompt(e); };
    window.addEventListener('beforeinstallprompt', handler);
    return () => window.removeEventListener('beforeinstallprompt', handler);
  }, []);
  React.useEffect(() => {
    if (screen === 'lineDetail') hasVisitedLineDetail.current = true;
    if (hasVisitedLineDetail.current && installPrompt && !showInstallBanner) {
      const dismissed = localStorage.getItem('pwa-install-dismissed');
      if (!dismissed) setShowInstallBanner(true);
    }
  }, [screen, installPrompt]); // eslint-disable-line

  const t = React.useCallback((k) => I18N[lang][k] || k, [lang]);

  React.useEffect(() => {
    if (theme === 'auto') {
      const mq = window.matchMedia('(prefers-color-scheme: dark)');
      const apply = () => document.documentElement.setAttribute('data-theme', mq.matches ? 'dark' : 'light');
      apply();
      mq.addEventListener('change', apply);
      return () => mq.removeEventListener('change', apply);
    } else {
      document.documentElement.setAttribute('data-theme', theme);
    }
  }, [theme]);
  React.useEffect(() => { localStorage.setItem('alsubte', JSON.stringify({ screen, params, theme, lang })); }, [screen, params, theme, lang]);
  React.useEffect(() => {
    localStorage.setItem('alsubte-push-prefs', JSON.stringify(pushPrefs));
    if (window.syncPushPrefsToIDB) window.syncPushPrefsToIDB(pushPrefs);
  }, [pushPrefs]);
  React.useEffect(() => {
    const handler = (e) => {
      if (e.data?.type === '__activate_edit_mode')   setTweaksOpen(true);
      if (e.data?.type === '__deactivate_edit_mode') setTweaksOpen(false);
    };
    window.addEventListener('message', handler);
    window.parent.postMessage({ type: '__edit_mode_available' }, '*');
    return () => window.removeEventListener('message', handler);
  }, []);

  // ── Browser history integration ───────────────────────────
  React.useEffect(() => {
    // Stamp the current entry so it has state (handles hard-reload / direct URL)
    window.history.replaceState(
      { screen: initial.screen || 'main', params: initial.params || {} },
      '',
      window.location.pathname + window.location.search
    );
    const onPop = (e) => {
      const st = e.state;
      if (st?.screen) { setScreen(st.screen); setParams(st.params || {}); }
      else            { setScreen('main');     setParams({}); }
    };
    window.addEventListener('popstate', onPop);
    return () => window.removeEventListener('popstate', onPop);
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  const go = React.useCallback((name, p = {}) => {
    setScreen(name);
    setParams(p);
    window.history.pushState({ screen: name, params: p }, '', window.location.pathname + window.location.search);
  }, []);
  const appProps = { go, t, theme, setTheme, lang, setLang, authed, setAuthed, pushPrefs, setPushPrefs, isDesktop };

  const renderScreen = () => {
    // Desktop main → full-width dashboard (no .page wrapper)
    if (isDesktop && screen === 'main')           return <DesktopHome {...appProps} />;
    if (isDesktop && screen === 'incidentReport') return <DesktopHome {...appProps} />;

    // Map is full-bleed at any size
    if (screen === 'map') return <ScreenMap {...appProps} />;

    // Every other screen gets centered + max-width on desktop via .page
    const narrow = (child) => <div className="page">{child}</div>;
    const wide   = (child) => <div className="page page-wide">{child}</div>;

    switch (screen) {
      case 'main':           return narrow(<ScreenMain {...appProps} />);
      case 'lineDetail':     return wide(<ScreenLineDetail lineId={params.line || 'A'} {...appProps} />);
      case 'news':           return narrow(<ScreenNews {...appProps} />);
      case 'chat':           return narrow(<ScreenChat {...appProps} />);
      case 'incidentReport': return narrow(<ScreenIncidentReport {...appProps} />);
      case 'about':          return narrow(<ScreenAbout {...appProps} />);
      case 'profile':        return narrow(<ScreenProfile {...appProps} />);
      case 'auth':           return narrow(<ScreenAuth {...appProps} />);
      case 'settings':       return narrow(<ScreenSettings {...appProps} />);
      case 'legal':          return narrow(<ScreenLegal doc={params.doc || 'terminos'} from={params.from || 'settings'} {...appProps} />);
      default:               return narrow(<ScreenMain {...appProps} />);
    }
  };

  const showBottomNav = !isDesktop &&
    !['lineDetail','chat','about','incidentReport','legal'].includes(screen);

  return (
    <div className="app-layout">
      {/* BETA ribbon — top-left corner, above everything */}
      <div style={{
        position: 'fixed', top: 0, left: 0, zIndex: 9999,
        width: 72, height: 72, overflow: 'hidden', pointerEvents: 'none',
      }}>
        <div style={{
          position: 'absolute', top: 4, left: -31, width: 96,
          background: '#CC3333', color: 'white',
          fontFamily: 'var(--font-display)', fontWeight: 1000, fontSize: 11,
          textAlign: 'center', padding: '4px 0', letterSpacing: '.12em',
          transform: 'rotate(-45deg)',
          boxShadow: '0 2px 6px rgba(0,0,0,.28)',
        }}>BETA</div>
      </div>

      {/* Sidebar — rendered by CSS only on ≥768px */}
      <AppSidebar screen={screen} go={go} t={t} authed={authed} />

      {/* Main content */}
      <div className="app-content">
        <div key={screen} className="screen-transition">{renderScreen()}</div>
        {showBottomNav && (
          <BottomNav
            active={screen}
            onChange={(id) => go(id)}
            t={t}
          />
        )}
      </div>

      {/* PWA install banner */}
      {showInstallBanner && (
        <div style={{
          position: 'fixed', bottom: showBottomNav ? 56 : 16, left: '50%', transform: 'translateX(-50%)',
          zIndex: 2000, background: 'var(--surface)', borderRadius: 16,
          boxShadow: 'var(--shadow-sm)', border: '1px solid var(--border)',
          padding: '12px 16px', display: 'flex', alignItems: 'center', gap: 12,
          maxWidth: 340, width: 'calc(100% - 32px)',
        }}>
          <Logo size={36} />
          <div style={{ flex: 1 }}>
            <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 13 }}>Instalar alSubte</div>
            <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>Acceso rápido desde tu pantalla</div>
          </div>
          <button onClick={() => {
            installPrompt.prompt();
            installPrompt.userChoice.then(() => { setShowInstallBanner(false); setInstallPrompt(null); });
          }} style={{ padding: '6px 14px', borderRadius: 8, background: 'var(--linea-a-2)', color: 'white', fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 12, border: 'none', flexShrink: 0 }}>
            Instalar
          </button>
          <button onClick={() => { setShowInstallBanner(false); localStorage.setItem('pwa-install-dismissed', '1'); }} style={{ width: 28, height: 28, borderRadius: 14, background: 'var(--ink-100)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, border: 'none' }}>
            <I name="x" size={14} />
          </button>
        </div>
      )}

      {/* Tweaks panel */}
      <div className={'tweaks' + (tweaksOpen ? ' open' : '')}>
        <h3>Tweaks</h3>
        <div className="tweak-row">
          <span>Tema</span>
          <div className="segmented">
            <button className={theme==='auto'?'active':''} onClick={() => saveTweak('theme','auto',setTheme)}>Auto</button>
            <button className={theme==='light'?'active':''} onClick={() => saveTweak('theme','light',setTheme)}>Claro</button>
            <button className={theme==='dark'?'active':''} onClick={() => saveTweak('theme','dark',setTheme)}>Oscuro</button>
          </div>
        </div>
        <div className="tweak-row">
          <span>Idioma</span>
          <div className="segmented">
            <button className={lang==='es'?'active':''} onClick={() => saveTweak('lang','es',setLang)}>ES</button>
            <button className={lang==='en'?'active':''} onClick={() => saveTweak('lang','en',setLang)}>EN</button>
          </div>
        </div>
      </div>
    </div>
  );
}

function saveTweak(key, val, setter) {
  setter(val);
  window.parent.postMessage({ type: '__edit_mode_set_keys', edits: { [key]: val } }, '*');
}

/* ── Sidebar ─────────────────────────────────────────────── */
function AppSidebar({ screen, go, t, authed }) {
  const items = [
    { id: 'main',      label: t('home'),     icon: 'home'    },
    { id: 'map',       label: t('map'),      icon: 'map'     },
    { id: 'news',      label: t('news'),     icon: 'news'    },
    { id: 'settings',  label: t('settings'), icon: 'settings'},
    { id: 'about',     label: t('about'),    icon: 'info'    },
  ];
  const activeId = ['lineDetail','incidentReport'].includes(screen) ? 'main' : screen;

  return (
    <aside className="app-sidebar">
      <div className="sidebar-logo"><Logo size={32} /></div>
      {items.map(it => (
        <button key={it.id} className={'sidebar-item' + (activeId === it.id ? ' active' : '')} onClick={() => go(it.id)}>
          <I name={it.icon} size={18} />
          <span>{it.label}</span>
        </button>
      ))}
      <div className="sidebar-footer">
        <span className="live-dot" /> Datos en vivo
      </div>
    </aside>
  );
}

/* ── Desktop home ────────────────────────────────────────── */
function DesktopHome({ go, t }) {
  const [tick, setTick] = React.useState(0);
  React.useEffect(() => { const i = setInterval(() => setTick(x=>x+1), 90); return ()=>clearInterval(i); }, []);
  const lineStatus = useLiveStatus();
  const wx = useWeather();

  const totalAlerts = Object.entries(lineStatus).filter(([id, s]) =>
    s.state !== 'normal' && getServiceState(id).state !== 'closed'
  ).length;
  const allClosedInfo = getAllClosedInfo();
  const [annDismissed, setAnnDismissed] = React.useState(() => loadDismissed());
  const activeAnns = React.useMemo(() => getActiveAnnouncements(annDismissed), [annDismissed, tick]);
  const dismissAnn = (id) => { const next = new Set(annDismissed); next.add(id); saveDismissed(next); setAnnDismissed(next); };

  const [statusEvents, setStatusEvents] = React.useState([]);
  React.useEffect(() => { loadStatusEvents(5).then(evs => setStatusEvents(evs || [])); }, []);

  return (
    <div className="scroll-area" style={{ padding: '28px 32px' }}>
      {/* Page header */}
      <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', marginBottom: 24 }}>
        <div>
          <h1 style={{ fontSize: 30, fontWeight: 800, letterSpacing: '-.02em' }}>Estado del Subte</h1>
          <div style={{ color: 'var(--text-muted)', fontSize: 13, marginTop: 4, display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
            <span style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
              <span className="live-dot" />{t('liveUpdate')} · {new Date().toLocaleTimeString('es-AR',{hour:'2-digit',minute:'2-digit'})}
            </span>
            {wx && (
              <span style={{ display: 'flex', alignItems: 'center', gap: 5, padding: '2px 10px 2px 6px', borderRadius: 999, background: 'var(--ink-100)', fontSize: 13 }}>
                <span style={{ fontSize: 17, lineHeight: 1 }}>{wx.icon}</span>
                <span style={{ fontFamily: 'var(--font-display)', fontWeight: 800 }}>{wx.temp}°</span>
                <span style={{ color: 'var(--text-dim)', fontWeight: 600 }}>ST {wx.feels}°</span>
                <span style={{ color: 'var(--text-dim)' }}>{wx.desc}</span>
              </span>
            )}
          </div>
        </div>
        <div style={{ display: 'flex', gap: 10 }}>
          <button className="btn btn-secondary"><I name="bell" size={16}/>{totalAlerts} alertas</button>
          <button className="btn btn-primary" onClick={() => go('map')}><I name="map" size={16}/>Mapa</button>
        </div>
      </div>

      {/* All-closed banner */}
      {allClosedInfo.allClosed && (
        <div style={{ padding: 14, borderRadius: 14, background: 'var(--ink-100)', color: 'var(--text)', display: 'flex', alignItems: 'center', gap: 10, marginBottom: 16 }}>
          <div style={{ width: 32, height: 32, borderRadius: 16, background: 'var(--ink-300)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <I name="moon" size={18} style={{ stroke: 'white' }} />
          </div>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 14, fontWeight: 700 }}>Servicio finalizado en toda la red</div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)' }}>Inicio del servicio nuevamente {allClosedInfo.opensDay} a las {allClosedInfo.opensAt}</div>
          </div>
        </div>
      )}

      {/* Anuncios trascendentales */}
      {activeAnns.length > 0 && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 16 }}>
          {activeAnns.map(a => <AnnouncementCard key={a.id} ann={a} onDismiss={() => dismissAnn(a.id)} />)}
        </div>
      )}

      {/* Line grid — 4 cols on wide, 3 on medium (via CSS class) */}
      <div className="lines-grid" style={{ display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 14, marginBottom: 24 }}>
        {LINES.map(line => {
          const st = lineStatus[line.id];
          const isDark = line.id === 'H' || line.id === 'P';
          const txt = isDark ? '#0B1220' : '#fff';
          const sub = isDark ? 'rgba(11,18,32,.7)' : 'rgba(255,255,255,.8)';
          const hasClosed = line.stations.some(s => CLOSED_TODAY.includes(s));
          const svc = getServiceState(line.id);
          const closed = svc.state === 'closed';
          const closingSoon = svc.state === 'closing-soon';
          const minsLeft = closingSoon ? Math.max(1, Math.round(svc.minsUntilClose)) : null;
          return (
            <button key={line.id} className={'grad-'+line.id.toLowerCase()} onClick={() => go('lineDetail',{line:line.id})}
              style={{ borderRadius: 18, padding: 18, color: txt, textAlign: 'left', minHeight: 155, display: 'flex', flexDirection: 'column', boxShadow: 'var(--shadow-md)', border: 'none', position: 'relative', overflow: 'hidden' }}>
              {hasClosed && <div style={{ position:'absolute', top:8, right:8, fontSize:9, padding:'2px 7px', borderRadius:999, background:'rgba(255,107,107,.9)', color:'white', fontFamily:'var(--font-display)', fontWeight:800 }}>CERRADA</div>}
              <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:10 }}>
                <div style={{ width:48,height:48,borderRadius:13,background:'rgba(255,255,255,.22)',display:'flex',alignItems:'center',justifyContent:'center',fontFamily:'var(--font-display)',fontWeight:800,fontSize:26 }}>{line.id}</div>
                <div style={{ width:8,height:8,borderRadius:4,background:closed?'rgba(255,255,255,.45)':closingSoon?'#FFE187':st.state==='normal'?'#86E8C9':st.state==='delay'?'#FFE187':'#FFB5B5' }} />
              </div>
              <div className={closingSoon ? 'blink' : ''} style={{ fontFamily:'var(--font-display)',fontWeight:700,fontSize:14 }}>
                {closed ? 'Fin del servicio' : closingSoon ? `⚠ Último tren en ${minsLeft} min` : st.state==='normal'?t('normalService'):st.state==='delay'?t('delays'):t('alert')}
              </div>
              <div style={{ fontSize:11,color:sub,marginTop:2 }}>{line.head1} ↔ {line.head2}</div>
              <div style={{ flex:1 }}/>
              <div style={{ fontSize:11,color:sub,borderTop:'1px solid rgba(255,255,255,.2)',paddingTop:7,marginTop:7 }}>
                {closed
                  ? <>1° tren {svc.opensDay}: <b style={{color:txt}}>{svc.opensAt}</b></>
                  : <>{t('frequency')}: <b style={{color:txt}}>{st.freq}</b></>}
              </div>
            </button>
          );
        })}
      </div>

      {/* Bottom: map + novedades/reportes */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 20 }}>
        <div className="card" style={{ padding: 20 }}>
          <h2 style={{ fontSize: 17, marginBottom: 14 }}>Mapa de la red</h2>
          <div style={{ height: 280, borderRadius: 12, overflow: 'hidden', background: 'var(--surface-2)' }}>
            <LeafletMap
              selectedLines={LINES.map(l => l.id)}
              showTrains={false}
              showEntrances={false}
              mini={true}
              onLineTap={() => go('map')}
            />
          </div>
          <button className="btn btn-secondary" style={{ marginTop: 12 }} onClick={() => go('map')}>Ver mapa interactivo <I name="arrowRight" size={14}/></button>
        </div>

        <div className="card" style={{ padding: 20, display:'flex', flexDirection:'column', maxHeight: 420, overflow:'hidden' }}>
          <h2 style={{ fontSize: 17, marginBottom: 14 }}>Novedades</h2>
          <div style={{ flex:1, overflowY:'auto' }}>
            {statusEvents.length === 0 ? (
              <div style={{ fontSize: 13, color: 'var(--text-dim)', padding: '8px 0' }}>Sin novedades en los últimos 5 días.</div>
            ) : (
              statusEvents.slice(0, 5).map((ev, i) => <StatusEventCard key={i} event={ev} />)
            )}
          </div>
          <button className="btn btn-ghost" style={{marginTop:8}} onClick={()=>go('news')}>Ver todas →</button>
        </div>
      </div>
    </div>
  );
}

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