/* global React, ReactDOM, Ic, OperationalDrawer, CommandPalette, useState, useEffect, useMemo, useRef,
   ScreenToday, ScreenTickets, ScreenCustomers, ScreenTelemetry, ScreenEngineering,
   ScreenResearch, ScreenGrants, ScreenInvestor, ScreenMarketing, ScreenContent,
   ScreenFinance, ScreenLegal, ScreenAutomation, ScreenMission, ScreenSettings */

const OPS_SECTIONS = ['summary', 'queue', 'customers', 'productHealth', 'engineering', 'marketing', 'documents', 'grants', 'investors', 'finance', 'legal', 'automations', 'settings'];

function initialSectionMap() {
  return Object.fromEntries(OPS_SECTIONS.map((section)=>[section, null]));
}

const NAV = [
  { n:'01', label:'Täna', icon:'today', items:[['Command Center','today'],['Minu otsused','today'],['Tähtajad','today'],['Riskid','today']] },
  { n:'02', label:'Piletid ja teated', icon:'inbox', items:[['Ühtne tööjärjekord','tickets'],['Triage','tickets'],['SLA ja vastamise järjekord','tickets'],['Allikad ja integratsioonid','tickets'],['Eskalatsioonid','tickets']] },
  { n:'03', label:'Kliendid', icon:'users', items:[['Kliendid','customers'],['Farmid','customers'],['Kasutajad','customers'],['Lepingud ja DPA','customers'],['Kliendi tervis','customers'],['Onboarding','customers'],['Arveldamine','customers']] },
  { n:'04', label:'Toode ja app', icon:'cube', items:[['app.agronutikas.ee telemeetria','telemetry'],['Kasutusanalüütika','telemetry'],['Veateated','telemetry'],['Offline/sync','telemetry'],['Kaardid ja põlluandmed','telemetry'],['Feature adoption','telemetry'],['Release health','telemetry']] },
  { n:'05', label:'Arendus', icon:'code', items:[['Repos','engineering'],['Deploy\u2019d','engineering'],['CI/CD','engineering'],['API tervis','engineering'],['Sõltuvused','engineering'],['Testid','engineering'],['Tehniline võlg','engineering'],['Incident playbooks','engineering']] },
  { n:'06', label:'Turundus', icon:'globe', items:[['agronutikas.ee ülevaade','marketing'],['Lehed','marketing'],['SEO','marketing'],['Vormid ja konversioonid','marketing'],['Kampaaniad','marketing'],['Claim audit','marketing']] },
  { n:'07', label:'Sisu ja meedia', icon:'layers', items:[['Blogi','content'],['Kodulehe tekstid','content'],['Pildid','content'],['Videod','content'],['Interaktiivsed tootetutvustused','content'],['CTA-d','content'],['Avaldamise workflow','content']] },
  { n:'08', label:'Research ja dokumendid', icon:'book', items:[['Markdown reader','research'],['Investor research','research'],['Tehnilised dokumendid','research'],['Strateegia','research'],['Õigusdokumendid','research'],['Missioon ja põhimõtted','mission'],['Decision log','research']] },
  { n:'09', label:'Toetused ja rahastus', icon:'coins', items:[['EIS RUP väike','grants'],['EIS RUP suur','grants'],['PRIA / muud toetused','grants'],['Taotluste staatus','grants'],['Eelarved','grants'],['Tähtajad','grants']] },
  { n:'10', label:'Investorid ja data room', icon:'vault', items:[['Investor readiness','investor'],['Data room','investor'],['Finantsmudel','finance'],['Runway','finance'],['Traction','investor'],['Due diligence','investor'],['Access log','investor']] },
  { n:'11', label:'Õigus ja compliance', icon:'shield', items:[['Asutajad','legal'],['IP assignment','legal'],['DPA/GDPR','legal'],['Turvariskid','legal'],['Audit log','legal'],['Andmekaitse','legal']] },
  { n:'12', label:'Seaded', icon:'settings', items:[['Integratsioonid','settings'],['Rollid ja õigused','settings'],['Teavitused','settings'],['Automaatikareeglid','automation'],['Audit','legal']] },
];

const SCREEN_GROUP = {}; // screen → group index
NAV.forEach((g,gi)=>g.items.forEach(it=>{ if(!(it[1] in SCREEN_GROUP)) SCREEN_GROUP[it[1]]=gi; }));

const CRUMBS = {
  today:['Täna','Command Center'], tickets:['Piletid ja teated','Ühtne tööjärjekord'], customers:['Kliendid','Customer 360'],
  telemetry:['Toode ja app','Telemeetria'], engineering:['Arendus','Developer Workspace'], marketing:['Turundus','agronutikas.ee'],
  content:['Sisu ja meedia','Content Studio'], research:['Research','Markdown reader'], grants:['Toetused','Grant administration'],
  investor:['Investorid','Data room'], finance:['Finants','Runway'], legal:['Õigus','Compliance'], automation:['Seaded','Automaatika'],
  mission:['Missioon','Põhimõtted'], settings:['Seaded','Integratsioonid'],
};
const TITLES = {
  today:'Täna', tickets:'Tööjärjekord', customers:'Kliendid', telemetry:'Telemeetria', engineering:'Arendus',
  marketing:'Turundus', content:'Sisu', research:'Research', grants:'Toetused', investor:'Investorid',
  finance:'Finants', legal:'Õigus', automation:'Automaatika', mission:'Missioon', settings:'Seaded',
};

function Sidebar({ screen, onNav }) {
  const activeGroup = SCREEN_GROUP[screen];
  const [open, setOpen] = useState({ [activeGroup]: true });
  useEffect(()=>{ setOpen(o=>({...o, [activeGroup]:true})); },[activeGroup]);
  return (
    <aside className="sb">
      <div className="sb-brand">
        <img src="wordmark-dark.svg" alt="AgroNutikas"/>
        <span className="sb-brand-chev"><Ic name="chevd"/></span>
      </div>
      <div className="sb-sub"><span>Operating Env · v8.1</span><b>OPS</b></div>
      <div className="sb-scroll">
        {NAV.map((g,gi)=>{
          const isOpen = open[gi];
          const isActiveGrp = gi===activeGroup;
          return (
            <div key={gi} className={`sb-group ${isActiveGrp?'is-active-grp':''}`}>
              <button className="sb-group-h" onClick={()=>setOpen(o=>({...o,[gi]:!o[gi]}))}>
                <Ic name={g.icon}/>
                <span>{g.label}</span>
                <span className="gidx">{isOpen?'–':g.n}</span>
              </button>
              {isOpen && (
                <div className="sb-items">
                  {g.items.map((it,ii)=>{
                    const isActive = screen===it[1] && (gi===activeGroup);
                    return (
                      <button key={ii} className={`sb-item ${isActive?'is-active':''}`} onClick={()=>onNav(it[1])}>
                        <span className="dotmark"/>
                        <span>{it[0]}</span>
                        <span/>
                      </button>
                    );
                  })}
                </div>
              )}
            </div>
          );
        })}
      </div>
      <div className="sb-foot">
        <div className="sb-user">
          <span className="sb-avatar">GL</span>
          <div><div className="sb-user-name">Gert Leisson</div><div className="sb-user-meta">Asutaja · Sr arendaja</div></div>
          <span style={{color:'var(--ink-muted)'}}><Ic name="chevd"/></span>
        </div>
      </div>
    </aside>
  );
}

function RoleToggle({ role, setRole }) {
  const roles = [['Asutaja','F'],['Arendaja','D'],['Tugi','T'],['Turundus','M'],['Investor','I']];
  return (
    <div className="sb-roles" title="Rolli vaade">
      {roles.map(r=>(<button key={r[0]} className={`sb-role ${role===r[0]?'is-on':''}`} onClick={()=>setRole(r[0])} title={r[0]}>{r[1]}</button>))}
    </div>
  );
}

function sectionStateLabel(payload, error) {
  if (error) return { text:'Viga', tone:'warn' };
  if (!payload) return { text:'Laeb', tone:'warn' };
  if (window.OpsProvenance.isMissing(payload)) return { text:'Puudub', tone:'warn' };
  if (window.OpsProvenance.isPartialLive(payload)) return { text:'Osaline', tone:'warn' };
  return { text:'REAL_API', tone:'ok' };
}

function Topbar({ screen, onSearch, role, setRole, opsPayloads, opsErrors }) {
  const c = CRUMBS[screen] || ['',''];
  const summary = sectionStateLabel(opsPayloads.summary, opsErrors.summary);
  const queue = sectionStateLabel(opsPayloads.queue, opsErrors.queue);
  return (
    <header className="tb">
      <div className="tb-title-block">
        <div className="tb-crumb"><b>{c[0]}</b><span className="sep">/</span><span>{c[1]}</span></div>
        <div className="tb-title">{TITLES[screen]}</div>
      </div>
      <button className="tb-search" onClick={onSearch}>
        <Ic name="search"/>
        <span>Otsi klienti, piletit, deploy’d, dokumenti, toetust…</span>
        <span className="k">⌘K</span>
      </button>
      <div className="tb-right">
        <div className="tb-stat hide-mobile"><span className="tb-stat-k">Kokkuvõte</span><span className={`tb-stat-v ${summary.tone}`}>{summary.text}</span></div>
        <div className="tb-stat hide-mobile"><span className="tb-stat-k">Järjekord</span><span className={`tb-stat-v ${queue.tone}`}>{queue.text}</span></div>
        <RoleToggle role={role} setRole={setRole}/>
        <button className="icon-btn"><Ic name="bell"/></button>
      </div>
    </header>
  );
}

function cleanRuntimeText(value, fallback='unknown') {
  return typeof value === 'string' && value.trim() ? value.trim() : fallback;
}

function cleanRuntimeNumber(value) {
  const parsed = typeof value === 'number' ? value : Number(value);
  return Number.isInteger(parsed) && parsed >= 0 ? parsed : 'unknown';
}

function cleanRuntimePr(value) {
  const parsed = typeof value === 'number' ? value : Number(value);
  return Number.isInteger(parsed) && parsed > 0 ? parsed : 'unknown';
}

function cleanRuntimeEnvironment(value) {
  return ['production','preview','development','test'].includes(value) ? value : 'unknown';
}

function normalizeFrontendMetadata(raw) {
  return {
    service: 'ops',
    version: cleanRuntimeText(raw && raw.version),
    build: cleanRuntimeNumber(raw && raw.build),
    commitSha: cleanRuntimeText(raw && raw.commitSha),
    branch: cleanRuntimeText(raw && raw.branch),
    prNumber: cleanRuntimePr(raw && raw.prNumber),
    builtAt: cleanRuntimeText(raw && raw.builtAt, 'unknown'),
    environment: cleanRuntimeEnvironment(raw && raw.environment),
  };
}

function normalizeBackendMetadata(raw) {
  if (!raw || typeof raw !== 'object') return null;
  return {
    service: 'api',
    version: cleanRuntimeText(raw.version),
    build: cleanRuntimeNumber(raw.build),
    commitSha: cleanRuntimeText(raw.commitSha),
    branch: cleanRuntimeText(raw.branch),
    prNumber: cleanRuntimePr(raw.prNumber),
    environment: cleanRuntimeEnvironment(raw.environment),
    deployedAt: cleanRuntimeText(raw.deployedAt),
    startedAt: cleanRuntimeText(raw.startedAt),
  };
}

function formatBackendVersion(backend) {
  if (!backend || backend.status === 'MISSING') return 'unknown';
  if (/-b\d+$/i.test(backend.version)) return backend.version;
  return typeof backend.build === 'number' ? `${backend.version}-b${backend.build}` : backend.version;
}

function apiBaseCategory() {
  const base = (window.OPS_CONFIG && window.OPS_CONFIG.apiBaseUrl) || 'https://api.agronutikas.ee';
  if (base.includes('localhost') || base.includes('127.0.0.1')) return 'local';
  if (base.includes('preview') || base.includes('vercel.app')) return 'preview';
  if (base.includes('api.agronutikas.ee')) return 'production';
  return 'unknown';
}

function RuntimeVersionPill({ screen }) {
  const [open, setOpen] = useState(false);
  const [copied, setCopied] = useState(false);
  const [backend, setBackend] = useState({ status:'MISSING', reason:'runtime metadata loading' });
  const [online, setOnline] = useState(typeof navigator === 'undefined' ? true : navigator.onLine);
  const stampRef = useRef(null);
  const closeRef = useRef(null);
  const correlationId = useRef(`rt-${Date.now().toString(36)}`);
  const frontend = useMemo(()=>normalizeFrontendMetadata(window.OE_RUNTIME_METADATA || {}), []);

  useEffect(()=>{
    let active = true;
    async function loadBackend() {
      try {
        const payload = await window.OpsApi.opsFetch('/v1/runtime');
        const normalized = normalizeBackendMetadata(payload);
        if (active) setBackend(normalized || { status:'MISSING', reason:'runtime metadata shape invalid' });
      } catch (error) {
        if (active) setBackend({ status:'MISSING', reason:'runtime metadata fetch failed' });
      }
    }
    loadBackend();
    const timer = setInterval(loadBackend, 60000);
    return ()=>{ active = false; clearInterval(timer); };
  },[]);

  useEffect(()=>{
    const update = ()=>setOnline(navigator.onLine);
    window.addEventListener('online', update);
    window.addEventListener('offline', update);
    return ()=>{
      window.removeEventListener('online', update);
      window.removeEventListener('offline', update);
    };
  },[]);

  useEffect(()=>{ if (open) closeRef.current && closeRef.current.focus(); },[open]);

  useEffect(()=>{
    if (!open) return undefined;
    const onKey = (event)=>{
      if (event.key === 'Escape') {
        event.preventDefault();
        closePanel();
      }
    };
    document.addEventListener('keydown', onKey);
    return ()=>document.removeEventListener('keydown', onKey);
  },[open]);

  function closePanel() {
    setOpen(false);
    stampRef.current && stampRef.current.focus();
  }

  const snapshot = useMemo(()=>({
    route: window.location.pathname || '/',
    screenId: screen,
    capturedAt: new Date().toISOString(),
    frontend,
    backend,
    apiBaseCategory: apiBaseCategory(),
    onlineState: online ? 'online' : 'offline',
    timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'unknown',
    correlationId: correlationId.current,
  }), [backend, frontend, online, screen]);

  const detail = useMemo(()=>JSON.stringify(snapshot, null, 2), [snapshot]);

  async function copyAndReport() {
    try {
      await navigator.clipboard?.writeText(detail);
      setCopied(true);
      setTimeout(()=>setCopied(false), 1800);
    } catch (error) {
      setCopied(false);
    }
  }

  return (
    <>
      <button
        ref={stampRef}
        type="button"
        className="runtime-stamp"
        aria-label="Runtime audit"
        onClick={()=>setOpen(true)}
        title="Runtime diagnostics"
      >
        OPS {frontend.version} <span aria-hidden="true">·</span> API {formatBackendVersion(backend)}
      </button>
      {open && (
        <div className="runtime-scrim" role="dialog" aria-modal="true" aria-label="Runtime diagnostics">
          <div className="runtime-panel">
            <div className="runtime-panel-head">
              <h2>Runtime diagnostics</h2>
              <div className="runtime-actions">
                <button className="runtime-action runtime-action-primary" type="button" onClick={copyAndReport}>
                  {copied ? 'Copied' : 'Copy and report'}
                </button>
                <button ref={closeRef} className="runtime-action" type="button" onClick={closePanel}>Sulge</button>
              </div>
            </div>
            <pre className="runtime-pre">{detail}</pre>
          </div>
        </div>
      )}
    </>
  );
}

function App() {
  const [screen, setScreen] = useState('today');
  const [drawerItem, setDrawerItem] = useState(null);
  const [cmdOpen, setCmdOpen] = useState(false);
  const [role, setRole] = useState('Asutaja');
  const [focus, setFocus] = useState(false);
  const [toast, setToast] = useState(null);
  const [opsPayloads, setOpsPayloads] = useState(initialSectionMap);
  const [opsErrors, setOpsErrors] = useState(initialSectionMap);

  const nav = (id)=>{ setScreen(id); setDrawerItem(null); setFocus(false); window.scrollTo&&window.scrollTo(0,0); };
  const openOp = (item)=> setDrawerItem(item);

  const reloadQueue = async ()=>{
    setOpsErrors(prev=>({ ...prev, queue: null }));
    try {
      const queue = await window.OpsDataSource.getQueue();
      setOpsPayloads(prev=>({ ...prev, queue }));
      return queue;
    } catch (error) {
      setOpsPayloads(prev=>({ ...prev, queue: null }));
      setOpsErrors(prev=>({ ...prev, queue: error }));
      throw error;
    }
  };

  useEffect(()=>{
    let active = true;
    const loadSection = async (sectionName)=>{
      try {
        const payload = await window.OpsDataSource.loadOpsSection(sectionName);
        if (!active) return;
        setOpsPayloads(prev=>({ ...prev, [sectionName]: payload }));
        setOpsErrors(prev=>({ ...prev, [sectionName]: null }));
      } catch (error) {
        if (!active) return;
        setOpsPayloads(prev=>({ ...prev, [sectionName]: null }));
        setOpsErrors(prev=>({ ...prev, [sectionName]: error }));
      }
    };
    OPS_SECTIONS.forEach(loadSection);
    return ()=>{ active = false; };
  },[]);

  useEffect(()=>{
    const h=(e)=>{ if((e.metaKey||e.ctrlKey)&&e.key.toLowerCase()==='k'){ e.preventDefault(); setCmdOpen(o=>!o); } };
    window.addEventListener('keydown',h); return ()=>window.removeEventListener('keydown',h);
  },[]);

  const doAction = (label, item)=>{ setToast(`${label} · ${item.id} — backend kirjutus pole selles vaates ühendatud`); setTimeout(()=>setToast(null), 2600); };

  const renderScreen = ()=>{
    switch(screen){
      case 'today': return <ScreenToday openOp={openOp} nav={nav} focus={focus} setFocus={setFocus} opsSummary={opsPayloads.summary} opsQueue={opsPayloads.queue} opsError={opsErrors.queue} opsSummaryError={opsErrors.summary}/>;
      case 'tickets': return <ScreenTickets openOp={openOp} selId={drawerItem&&drawerItem.id} opsQueue={opsPayloads.queue} opsError={opsErrors.queue} reloadQueue={reloadQueue}/>;
      case 'customers': return <ScreenCustomers opsPayload={opsPayloads.customers} opsError={opsErrors.customers}/>;
      case 'telemetry': return <ScreenTelemetry opsPayload={opsPayloads.productHealth} opsError={opsErrors.productHealth}/>;
      case 'engineering': return <ScreenEngineering opsPayload={opsPayloads.engineering} opsError={opsErrors.engineering}/>;
      case 'marketing': return <ScreenMarketing opsPayload={opsPayloads.marketing} opsError={opsErrors.marketing}/>;
      case 'content': return <ScreenContent opsPayload={opsPayloads.documents} opsError={opsErrors.documents}/>;
      case 'research': return <ScreenResearch opsPayload={opsPayloads.documents} opsError={opsErrors.documents}/>;
      case 'grants': return <ScreenGrants opsPayload={opsPayloads.grants} opsError={opsErrors.grants}/>;
      case 'investor': return <ScreenInvestor opsPayload={opsPayloads.investors} opsError={opsErrors.investors}/>;
      case 'finance': return <ScreenFinance opsPayload={opsPayloads.finance} opsError={opsErrors.finance}/>;
      case 'legal': return <ScreenLegal opsPayload={opsPayloads.legal} opsError={opsErrors.legal}/>;
      case 'automation': return <ScreenAutomation opsPayload={opsPayloads.automations} opsError={opsErrors.automations}/>;
      case 'mission': return <ScreenMission opsPayload={opsPayloads.summary} opsError={opsErrors.summary}/>;
      case 'settings': return <ScreenSettings opsPayload={opsPayloads.settings} opsError={opsErrors.settings}/>;
      default: return <ScreenToday openOp={openOp} nav={nav} focus={focus} setFocus={setFocus} opsSummary={opsPayloads.summary} opsQueue={opsPayloads.queue} opsError={opsErrors.queue} opsSummaryError={opsErrors.summary}/>;
    }
  };

  return (
    <div className={`app ${drawerItem?'drawer-open':''}`}>
      <Sidebar screen={screen} onNav={nav}/>
      <div className="app-main">
        <Topbar screen={screen} onSearch={()=>setCmdOpen(true)} role={role} setRole={setRole} opsPayloads={opsPayloads} opsErrors={opsErrors}/>
        <div className="app-body">{renderScreen()}</div>
      </div>
      {drawerItem && <OperationalDrawer item={drawerItem} onClose={()=>setDrawerItem(null)} onAction={doAction}/>}
      <CommandPalette open={cmdOpen} onClose={()=>setCmdOpen(false)} onNav={nav}/>
      <RuntimeVersionPill screen={screen}/>
      {toast && <div style={{position:'fixed', bottom:'18px', left:'50%', transform:'translateX(-50%)', background:'var(--bg-2)', border:'1px solid var(--signal)', color:'var(--ink-hi)', padding:'10px 16px', fontSize:'12px', fontFamily:'var(--mono)', letterSpacing:'0.03em', zIndex:1200, boxShadow:'0 8px 30px rgba(0,0,0,0.5)'}}>{toast}</div>}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
