/* global React, Ic, Chip, StatusChip, PTag, Fresh, Sec, Box, StatStrip, Tabs, State, useState, window */

/* ════ SCREEN 2 · Unified ticketing + notifications ════ */
function normalizeTicketPriority(priority) {
  const raw = String(priority || '').toUpperCase();
  if (['P0', 'P1', 'P2', 'P3'].includes(raw)) return raw;
  if (raw === 'CRITICAL') return 'P0';
  if (raw === 'HIGH') return 'P1';
  if (raw === 'MEDIUM') return 'P2';
  return 'P3';
}

function formatTicketUpdatedAt(value) {
  if (!value) return '—';
  const parsed = new Date(value);
  if (Number.isNaN(parsed.getTime())) return String(value);
  return parsed.toLocaleString('et-EE', { day:'2-digit', month:'2-digit', hour:'2-digit', minute:'2-digit' });
}

function getQueueItems(opsQueue) {
  return Array.isArray(opsQueue?.data?.items) ? opsQueue.data.items : [];
}

function isMalformedQueue(opsQueue) {
  return Boolean(opsQueue?.data && !Array.isArray(opsQueue.data.items));
}

function getQueueMeta(opsQueue, opsError) {
  if (opsError) {
    return { ok:false, label:'Viga', tone:'danger', fresh:'missing', detail:opsError.message || 'backend queue päring ebaõnnestus' };
  }
  if (!opsQueue) {
    return { ok:false, label:'Laeb', tone:'warn', fresh:'missing', detail:'backend queue laeb' };
  }
  if (window.OpsProvenance.isMissing(opsQueue)) {
    return { ok:false, label:'Puudub', tone:'danger', fresh:'missing', detail:opsQueue.provenance.detail || 'backend queue allikas puudub' };
  }
  if (isMalformedQueue(opsQueue)) {
    return { ok:false, label:'Vigane kuju', tone:'danger', fresh:'missing', detail:'backend queue items ei ole massiiv' };
  }
  if (window.OpsProvenance.isPartialLive(opsQueue)) {
    return { ok:true, label:'Osaliselt live', tone:'warn', fresh:'stale', detail:opsQueue.provenance.detail || 'backend queue on osaline' };
  }
  return { ok:true, label:'Live', tone:'', fresh:'live', detail:'backend queue' };
}

function statValue(queueMeta, value) {
  return queueMeta.ok ? value : '—';
}

function toTicketQueueItem(item, index) {
  const id = item.id == null ? '' : String(item.id).trim();
  const status = item.status || 'Staatus puudub';
  return {
    ...item,
    id,
    uiKey: id || `missing-id-${index}`,
    canTriage: Boolean(id),
    P: normalizeTicketPriority(item.priority),
    title: item.title || id || 'Pealkiri puudub',
    source: item.source || 'Allikas puudub',
    customer: item.customer || '—',
    status,
    updatedLabel: formatTicketUpdatedAt(item.updatedAt),
    next: 'Triage',
  };
}

function ScreenTickets({ openOp, selId, opsQueue, opsError, reloadQueue }) {
  const [filter, setFilter] = useState('all');
  const [view, setView] = useState('queue');
  const [triage, setTriage] = useState({ pendingId: null, error: null });
  const queueMeta = getQueueMeta(opsQueue, opsError);
  const items = getQueueItems(opsQueue).map(toTicketQueueItem);
  const counts = ['P0','P1','P2','P3'].reduce((acc, key)=>{
    acc[key] = items.filter((i)=>i.P === key).length;
    return acc;
  }, { all: items.length });
  const rows = items.filter(i => filter==='all' || i.P===filter);
  const sources = [...new Set(items.map(i=>i.source))];
  const malformedState = isMalformedQueue(opsQueue) ? <State icon="alert" title="Backend queue kuju ei sobi" sub="Oodati data.items massiivi. Kirjeid ei kuvata enne, kui backend leping on parandatud."/> : null;
  const opsState = malformedState || window.OpsScreenState.renderOpsState(opsQueue, opsError);
  const emptyState = !opsState && items.length === 0 ? <State icon="inbox" title="Backend järjekord on tühi" sub="Autoriteetne queue allikas ei tagastanud hetkel kirjeid."/> : null;
  const latestUpdate = items.map((item)=>item.updatedAt).filter(Boolean).sort().at(-1);

  const runTriage = async (event, item)=>{
    event.stopPropagation();
    if (!reloadQueue || triage.pendingId) return;
    if (!item.canTriage) {
      setTriage({ pendingId: null, error: new Error('Triage blokeeritud: backend queue kirjel puudub id.') });
      return;
    }
    const status = 'triaged';
    setTriage({ pendingId: item.id, error: null });
    try {
      await window.OpsDataSource.triageQueueItem(item.id, {
        idempotencyKey: `oe-triage-${item.id}-${status}`,
        status,
        note: 'Triage märgitud Operation Environment tööjärjekorra vaatest.',
      });
      await reloadQueue();
      setTriage({ pendingId: null, error: null });
    } catch (error) {
      setTriage({ pendingId: null, error });
    }
  };

  return (
    <div className="page">
      <div className="page-intro">
        <div>
          <span className="ov">Piletid ja teated · Ühtne tööjärjekord</span>
          <h1>Üks prioriteetne järjekord</h1>
          <p className="lede">GitHub, Sentry, CI/CD, toe e-post, veebivormid, telemeetria, kalendritähtajad, investori- ja toetusülesanded — kõik muutub üheks selgitatava prioriteediga operational item’iks.</p>
        </div>
        <div className="page-actions"><button className="btn"><Ic name="plus"/>Käsitsi ülesanne</button><button className="btn btn-primary"><Ic name="robot"/>AI triage</button></div>
      </div>

      <StatStrip cols items={[
        { k:'Kokku järjekorras', v:queueMeta.ok ? items.length : queueMeta.label, tone:queueMeta.ok ? '' : queueMeta.tone, sub:queueMeta.ok ? 'backend queue' : queueMeta.detail, fresh:queueMeta.fresh },
        { k:'P0', v:statValue(queueMeta, counts.P0), tone:queueMeta.ok ? 'danger' : queueMeta.tone, sub:'kriitiline', fresh:queueMeta.fresh },
        { k:'P1', v:statValue(queueMeta, counts.P1), tone:queueMeta.ok ? 'warn' : queueMeta.tone, sub:'kõrge', fresh:queueMeta.fresh },
        { k:'P2/P3', v:statValue(queueMeta, counts.P2 + counts.P3), tone:queueMeta.ok ? '' : queueMeta.tone, sub:'madalam prio', fresh:queueMeta.fresh },
        { k:'Allikaid', v:statValue(queueMeta, sources.length), tone:queueMeta.ok ? '' : queueMeta.tone, sub:'integratsiooni', fresh:queueMeta.fresh },
        { k:'Backend', v:queueMeta.ok ? (opsQueue?.provenance?.kind || queueMeta.label) : queueMeta.label, tone:queueMeta.tone, fresh:queueMeta.fresh },
        { k:'Staatusi', v:statValue(queueMeta, new Set(items.map((item)=>item.status)).size), tone:queueMeta.ok ? '' : queueMeta.tone, sub:'queue väärtust', fresh:queueMeta.fresh },
        { k:'Viim. uuendus', v:queueMeta.ok ? formatTicketUpdatedAt(latestUpdate) : '—', tone:queueMeta.ok ? '' : queueMeta.tone, sub:'updatedAt', fresh:latestUpdate && queueMeta.ok ? queueMeta.fresh : 'missing' },
      ]}/>

      <Tabs value={view} onChange={setView} items={[
        {id:'queue', label:'Tööjärjekord', count:queueMeta.ok ? rows.length : null},
        {id:'triage', label:'Triage'},
        {id:'sla', label:'SLA järjekord'},
        {id:'sources', label:'Allikad', count:queueMeta.ok ? sources.length : null},
      ]}/>

      <div className="toolbar">
        <label className="search"><Ic name="search"/><input placeholder="Otsi ID, klient, allikas, pind…"/></label>
        {[['all','Kõik'],['P0','P0'],['P1','P1'],['P2','P2'],['P3','P3']].map(([k,l])=>(
          <button key={k} className={`fbtn ${filter===k?'is-on':''}`} onClick={()=>setFilter(k)}>{l}<span className="c">{queueMeta.ok ? counts[k] : '—'}</span></button>
        ))}
      </div>

      {triage.error && <State icon="alert" title="Triage ebaõnnestus" sub={triage.error.message || 'Backend kirjutus ebaõnnestus.'}/>}

      {view==='sources' ? (
        <div className="cardgrid c3">
          {opsState}
          {emptyState}
          {sources.map(s=>{
            const its = items.filter(i=>i.source===s);
            return <Box key={s} ov="Allikas" title={s} right={<Chip tone="ok" icon="check">Ühendatud</Chip>}>
              <dl className="kv"><dt>Kirjeid</dt><dd><b>{its.length}</b></dd><dt>Kõrgeim</dt><dd><PTag p={its[0]?.P || 'P3'}/></dd><dt>Viim. uuendus</dt><dd className="mono">{formatTicketUpdatedAt(its.map((it)=>it.updatedAt).filter(Boolean).sort().at(-1))}</dd></dl>
            </Box>;
          })}
        </div>
      ) : view==='triage' ? (
        <div className="cardgrid c4" style={{alignItems:'start'}}>
          {opsState}
          {emptyState}
          {['P0','P1','P2','P3'].map(p=>(
            <div key={p} style={{border:'1px solid var(--line-strong)', background:'var(--bg-1)'}}>
              <div className="spread" style={{padding:'9px 11px', borderBottom:'1px solid var(--line-strong)'}}><PTag p={p}/><span className="mono muted" style={{fontSize:'10px'}}>{queueMeta.ok ? counts[p] : '—'}</span></div>
              {items.filter(i=>i.P===p).map(it=>(
                <button key={it.uiKey} onClick={()=>openOp(it)} style={{display:'block', width:'100%', textAlign:'left', padding:'9px 11px', borderBottom:'1px solid var(--line)', background:'transparent', color:'inherit'}}>
                  <div style={{fontSize:'11.5px', color:'var(--ink-hi)', fontWeight:600, lineHeight:1.35}}>{it.title}</div>
                  <div className="mono" style={{fontSize:'9px', color:'var(--ink-muted)', marginTop:'4px', letterSpacing:'0.04em'}}>{it.id || 'ID puudub'} · {it.source} · {it.status}</div>
                </button>
              ))}
            </div>
          ))}
        </div>
      ) : (
        <div className="scroll-x">
          {opsState}
          {emptyState}
          <table className="t">
            <thead><tr>
              <th>Prio</th><th>Kirje</th><th>Allikas</th><th>Klient</th><th>Uuendatud</th><th>Backend ID</th><th>Staatus</th><th>Prioriteet</th><th>Tegevus</th>
            </tr></thead>
            <tbody>
              {rows.map(it=>(
                <tr key={it.uiKey} className={selId===it.id?'sel':''} onClick={()=>openOp(it)}>
                  <td><PTag p={it.P}/></td>
                  <td><div className="name"><b>{it.title}</b><small>{it.id || 'ID puudub'} · {it.source}</small></div></td>
                  <td><span className="mono">{it.source}</span></td>
                  <td style={{maxWidth:'160px'}}>{it.customer}</td>
                  <td>{it.updatedLabel !== '—' ? <Chip tone="mute" icon="clock">{it.updatedLabel}</Chip> : <span className="muted mono">—</span>}</td>
                  <td className="mono">{it.id || 'ID puudub'}</td>
                  <td><StatusChip status={it.status}/></td>
                  <td className="num"><b>{it.P}</b></td>
                  <td><button className="btn btn-sm" disabled={!it.canTriage || triage.pendingId === it.id} onClick={(event)=>runTriage(event, it)}><Ic name="flag"/>{triage.pendingId === it.id ? 'Salvestan' : it.canTriage ? it.next : 'ID puudub'}</button></td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

function isPlainRecord(value) {
  return value && typeof value === 'object' && !Array.isArray(value);
}

const EXACT_SENSITIVE_BACKEND_KEYS = new Set([
  'token',
  'secret',
  'password',
  'apikey',
  'apiKey',
  'api_key',
  'auth',
  'bearer',
  'cookie',
  'session',
  'ssn',
  'isikukood',
  'personalcode',
  'personalCode',
  'email',
  'phone',
  'address',
  'ip',
  'useragent',
  'userAgent',
  'auditlog',
  'auditLog',
  'audit',
  'accesslog',
  'accessLog',
  'raw',
  'payload',
].map((key)=>key.toLowerCase().replace(/[^a-z0-9]/g, '')));
const CONTAINED_SENSITIVE_BACKEND_KEYS = [
  'token',
  'secret',
  'password',
  'apikey',
  'bearer',
  'cookie',
  'session',
  'ssn',
  'isikukood',
  'personalcode',
  'email',
  'phone',
  'address',
  'useragent',
  'auditlog',
  'accesslog',
  'payload',
];

function normalizeBackendKey(key) {
  return String(key || '').toLowerCase().replace(/[^a-z0-9]/g, '');
}

function isSensitiveBackendKey(key) {
  const normalized = normalizeBackendKey(key);
  return EXACT_SENSITIVE_BACKEND_KEYS.has(normalized)
    || CONTAINED_SENSITIVE_BACKEND_KEYS.some((sensitiveKey)=>normalized.includes(sensitiveKey))
    || normalized.endsWith('ip');
}

function truncateDisplayString(value) {
  const text = String(value);
  return text.length > 96 ? `${text.slice(0, 93)}...` : text;
}

function displayValue(value, key) {
  if (isSensitiveBackendKey(key)) return 'Peidetud';
  if (value == null || value === '') return '—';
  if (typeof value === 'boolean') return value ? 'Jah' : 'Ei';
  if (typeof value === 'number') return Number.isFinite(value) ? String(value) : '—';
  if (typeof value === 'string') return truncateDisplayString(value);
  if (Array.isArray(value)) return `${value.length} kirjet`;
  if (isPlainRecord(value)) return 'Objekt (toetamata)';
  return 'Väärtus (toetamata)';
}

function humanizeKey(key) {
  return String(key).replace(/([a-z])([A-Z])/g, '$1 $2').replace(/[_-]+/g, ' ');
}

function collectOpsCollections(data) {
  if (!isPlainRecord(data)) return [];
  return Object.entries(data)
    .filter(([key, value]) => !isSensitiveBackendKey(key) && Array.isArray(value))
    .map(([key, rows]) => {
      if (rows.length === 0 || rows.every(isPlainRecord)) return { key, kind:'records', rows };
      return { key, kind:'unsupported-array', rows: [] };
    });
}

function collectOpsScalars(data) {
  if (!isPlainRecord(data)) return [];
  return Object.entries(data)
    .filter(([key, value]) => !isSensitiveBackendKey(key) && (value == null || ['string', 'number', 'boolean'].includes(typeof value)))
    .slice(0, 8)
    .map(([key, value]) => ({ k: humanizeKey(key), v: displayValue(value, key), fresh:'live' }));
}

function BackendCollectionTable({ collection }) {
  if (collection.kind === 'unsupported-array') {
    return <State icon="alert" title={`${humanizeKey(collection.key)} on toetamata massiiv`} sub="Backend tagastas primitiivide või segatüüpi massiivi. Seda ei kuvata tabelina, et vältida eksitavat või tundlikku väljundit."/>;
  }
  const rows = collection.rows.slice(0, 50);
  const columns = [...new Set(rows.flatMap((row)=>Object.keys(row).filter((key)=>!isSensitiveBackendKey(key) && !isPlainRecord(row[key]))))].slice(0, 8);
  if (rows.length === 0 || columns.length === 0) {
    return <State icon="inbox" title={`${humanizeKey(collection.key)} ei sisalda ohutuid ridu`} sub="Backend tagastas tühja massiivi või ainult peidetud/toetamata veerud."/>;
  }
  return (
    <div className="scroll-x">
      <table className="t">
        <thead><tr>{columns.map((column)=><th key={column}>{humanizeKey(column)}</th>)}</tr></thead>
        <tbody>
          {rows.map((row, index)=>(
            <tr key={row.id || `${collection.key}-${index}`}>
              {columns.map((column)=><td key={column} className={typeof row[column] === 'number' ? 'num' : undefined}>{displayValue(row[column], column)}</td>)}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

function GenericOpsScreen({ sectionName, payload, error, eyebrow, title, description }) {
  const state = window.OpsScreenState.renderOpsState(payload, error);
  const collections = collectOpsCollections(payload?.data);
  const scalars = collectOpsScalars(payload?.data);
  const hasRenderableData = collections.length > 0 || scalars.length > 0;

  return (
    <div className="page">
      <div className="page-intro">
        <div>
          <span className="ov">{eyebrow}</span>
          <h1>{title}</h1>
          <p className="lede">{description}</p>
        </div>
        <div className="page-actions">
          <Chip tone={state ? 'warn' : 'ok'} icon={state ? 'alert' : 'check'}>{payload?.provenance?.kind || (error ? 'ERROR' : 'LOADING')}</Chip>
        </div>
      </div>

      {state}
      {!state && !hasRenderableData && <State icon="doc" title="Backend payload on tühi või tundmatu" sub={`${sectionName} tagastas REAL_API oleku, kuid data plokk ei sisalda kuvatavaid ridu, kaarte ega lihtsaid mõõdikuid.`}/>}
      {!state && scalars.length > 0 && <StatStrip cols items={scalars}/>}
      {!state && collections.map((collection)=>(
        <Sec key={collection.key} ov={sectionName} title={humanizeKey(collection.key)} meta={collection.kind === 'records' ? `${collection.rows.length} kirjet` : 'toetamata kuju'} flush>
          <BackendCollectionTable collection={collection}/>
        </Sec>
      ))}
    </div>
  );
}

function ScreenCustomers({ opsPayload, opsError }) {
  return <GenericOpsScreen sectionName="customers" payload={opsPayload} error={opsError} eyebrow="Kliendid · Customer 360" title="Kliendid, farmid, lepingud, tervis" description="Vaade kuvab ainult autoriteetse customers backend jaotise andmeid või selget puudumise olekut."/>;
}

function ScreenTelemetry({ opsPayload, opsError }) {
  return <GenericOpsScreen sectionName="productHealth" payload={opsPayload} error={opsError} eyebrow="Toode ja app · telemeetria" title="Toote kasutus ja tervis" description="Telemeetria tuleb product health backend jaotisest. Kui allikas puudub või kuju muutub, kuvatakse eksplitsiitne olek."/>;
}

function ScreenEngineering({ opsPayload, opsError }) {
  return <GenericOpsScreen sectionName="engineering" payload={opsPayload} error={opsError} eyebrow="Arendus · Developer Workspace" title="Kood, deploy, testid, API tervis" description="Arendusvaade ei oleta deploy, CI ega repo seise. Kõik read pärinevad engineering backend jaotisest."/>;
}

Object.assign(window, { ScreenTickets, ScreenCustomers, ScreenTelemetry, ScreenEngineering, GenericOpsScreen, collectOpsCollections, collectOpsScalars });
