// Integrações: grid de cards com status, última sync e saúde; Drawer com logs e permissão necessária.
// A integração "Base pública de oportunidades" mostra status e logs reais (data_sync_runs / data_sync_sources); as demais
// ainda são ilustrativas (configurar/desconectar só disparam Toast). Credenciais nunca aparecem na UI.
function IntegrationsScreen() {
  const { PageHeader, Card, Badge, Drawer, DataField, EmptyState, StatusDot, Alert } = window.VRticeDesignSystem_d763eb;
  const { toast } = useShell();
  const A = window.VXAdmin;
  const [open, setOpen] = React.useState(null);
  const [pncpCnpj, setPncpCnpj] = React.useState('');
  const [pncpFrom, setPncpFrom] = React.useState('');
  const [pncpTo, setPncpTo] = React.useState('');
  const [pncpBusy, setPncpBusy] = React.useState(false);
  const [pncpResult, setPncpResult] = React.useState('');
  const [pncpSummary, setPncpSummary] = React.useState(null);
  // Result evidence and contract confirmation are distinct statements (mirrors describeEvidence in supabase/functions/_shared).
  const evidenceLabel = p => p.contractConfirmed ? ['Contrato confirmado','success'] : p.resultStatus==='CANCELADO' ? ['Resultado cancelado','danger'] : p.resultStatus==='SEM_VALOR_HOMOLOGADO' ? ['Resultado encontrado · sem valor homologado','warning'] : ['Resultado encontrado · contrato não localizado','info'];
  const promoLabel = e => !e ? null : e.enriched ? ['Conta promovida e score atualizado','success'] : e.promotionStatus==='SKIPPED_NO_RESULTS' ? ['Sem resultados · conta não criada','neutral'] : e.promotionStatus==='FORBIDDEN' ? ['Sem permissão para promover conta','warning'] : e.promotionStatus==='PROMOTED' ? ['Conta promovida · score pendente','warning'] : ['Promoção não concluída','danger'];
  const [syncSources,setSyncSources]=React.useState([]);
  const [runs,setRuns]=React.useState(null);
  const [discBusy,setDiscBusy]=React.useState(false);
  const [discMsg,setDiscMsg]=React.useState(null);
  const reload=React.useCallback(()=>{const V=window.VxSalesIntelligence;V?.listSyncSources?.().then(setSyncSources);V?.listSyncRuns?.(40).then(r=>setRuns(r||[]))},[]);
  React.useEffect(()=>{reload()},[pncpResult,reload]);
  // Chamada autenticada à Edge Function com a sessão do usuário (RBAC integrations.manage valida no servidor).
  const callSync = async extra => {
    const cfg = window.VX_SUPABASE || {};
    if (!window.supabase?.createClient || !cfg.url || !cfg.anonKey) throw new Error('Supabase não configurado neste ambiente.');
    const client = window.supabase.createClient(cfg.url, cfg.anonKey, { auth:{persistSession:true,autoRefreshToken:true} });
    const {data:s} = await client.auth.getSession();
    const user = s?.session?.user;
    if (!user) throw new Error('Sessão não encontrada.');
    const {data:ctx,error:ce} = await client.from('user_active_contexts').select('organization_id,environment_id').eq('user_id',user.id).single();
    if (ce) throw ce;
    const {data,error} = await client.functions.invoke('pncp-sync',{body:{organizationId:ctx.organization_id,environmentId:ctx.environment_id,...extra}});
    if (error) throw error;
    return data;
  };
  const runPncp = async () => {
    setPncpBusy(true); setPncpResult(''); setPncpSummary(null);
    try {
      const data = await callSync({cnpj:pncpCnpj,dataInicial:pncpFrom||undefined,dataFinal:pncpTo||undefined});
      setPncpSummary(data); setPncpResult(JSON.stringify(data));
    } catch(e) { setPncpResult('ERRO: '+(e.message||String(e))); } finally { setPncpBusy(false); }
  };
  // Atualização direta: roda um ciclo de descoberta/enriquecimento agora, sem esperar o agendamento.
  const runDiscover = async () => {
    setDiscBusy(true); setDiscMsg(null);
    try {
      const d = await callSync({action:'discover'});
      if (d?.skipped) setDiscMsg(['neutral','Descoberta desligada para este ambiente ('+d.skipped+').']);
      else setDiscMsg([d.ok?'success':'warning','Ciclo concluído · '+(d.sourceStatus||'—')+' · '+(d.discovery?.scanned||0)+' registros lidos'+(d.error?' · '+d.error:'')]);
    } catch(e) { setDiscMsg(['warning','Não foi possível confirmar o ciclo ('+(e.message||String(e))+'). Ele pode ter continuado no servidor; confira o histórico abaixo em instantes.']); }
    finally { setDiscBusy(false); reload(); }
  };
  // Status real da base pública: último ciclo de descoberta (Compras.gov) + última verificação de saúde do PNCP.
  const ago = iso => { if (!iso) return '—'; const m = Math.max(0, Math.round((Date.now() - new Date(iso).getTime()) / 60000)); return m < 1 ? 'agora' : m < 60 ? 'há ' + m + ' min' : m < 1440 ? 'há ' + Math.round(m / 60) + ' h' : 'há ' + Math.round(m / 1440) + ' d'; };
  const discRun = (runs || []).find(r => r.provider === 'COMPRAS_GOV' && r.trigger !== 'HEALTHCHECK');
  const healthRun = (runs || []).find(r => r.provider === 'PNCP' && r.trigger === 'HEALTHCHECK');
  const pubInfo = (() => {
    if (runs === null) return { status: 'Verificando', tone: 'neutral', sync: '—', health: 'Consultando execuções reais…' };
    if (!discRun && !healthRun) return { status: 'Sem execuções', tone: 'neutral', sync: '—', health: 'Nenhuma execução registrada' };
    if (healthRun && healthRun.status !== 'SUCCESS') return { status: 'Degradada', tone: 'warning', sync: ago(discRun?.started_at), health: 'PNCP indisponível na última verificação (' + (healthRun.status || '—') + ')' };
    if (discRun && (discRun.status === 'ERROR' || discRun.status === 'UPSTREAM_UNAVAILABLE')) return { status: 'Com falha', tone: 'danger', sync: ago(discRun.started_at), health: 'Último ciclo: ' + discRun.status };
    return { status: 'Conectado', tone: 'success', sync: ago(discRun?.started_at), health: discRun?.status === 'PARTIAL' ? 'Último ciclo parcial: continua no próximo' : 'Saudável' };
  })();
  const integrations = A.INTEGRATIONS.map(x => x.id === 'public' ? { ...x, ...pubInfo } : x);
  const it = integrations.find(x => x.id === open);
  const RUN_LABEL = { COMPRAS_GOV: 'Descoberta Compras.gov', PNCP: 'PNCP' }, TRIG_LABEL = { SCHEDULED: 'automático', MANUAL: 'manual', HEALTHCHECK: 'verificação de saúde' };
  const fmt = iso => new Date(iso).toLocaleString('pt-BR', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });
  const logs = it && it.id === 'public' ? (runs || []).slice(0, 8).map(r => [r.id, fmt(r.started_at), r.status === 'SUCCESS' ? 'success' : r.status === 'PARTIAL' ? 'warning' : 'danger',
    (RUN_LABEL[r.provider] || r.provider) + ' · ' + (TRIG_LABEL[r.trigger] || r.trigger) + ' · ' + r.status + (r.records_read ? ' · ' + r.records_read + ' lidos' : '')]) : [];
  return (
    <BlockGrid.Auto id="integrations">
      <PageHeader size="lg" eyebrow="ADMINISTRAÇÃO" title="Integrações" description="Conexões com serviços externos: status, última sincronização e saúde." />
      <Card variant="analysis" padding={24} gap={14} style={{ marginBottom: 20 }}>
        <div style={{display:'flex',justifyContent:'space-between',alignItems:'center',gap:16,flexWrap:'wrap'}}>
          <div><span style={vxEyebrow}>PNCP · EXECUÇÃO REAL</span><strong style={{display:'block',fontSize:16,marginTop:6}}>Sincronização autenticada</strong><span style={{display:'block',fontSize:13,color:'var(--text-muted)',marginTop:4}}>Executa a Edge Function com a sua sessão e permissão integrations.manage. Nenhuma credencial aparece no navegador.</span></div>
          <div style={{display:'flex',gap:10,flexWrap:'wrap'}}>
            <PBtn perm="integrations.manage" icon="ph-arrows-clockwise" onClick={runDiscover} disabled={discBusy}>{discBusy ? 'Atualizando… (até 2 min)' : 'Atualizar dados agora'}</PBtn>
            <PBtn perm="integrations.manage" variant="secondary" onClick={runPncp} disabled={pncpBusy || !pncpCnpj}>{pncpBusy ? 'Sincronizando…' : 'Sincronizar CNPJ'}</PBtn>
          </div>
        </div>
        {discMsg && <Alert tone={discMsg[0]==='success'?'success':discMsg[0]==='warning'?'warning':'info'}>{discMsg[1]}</Alert>}
        <div style={{display:'grid',gridTemplateColumns:'1.2fr 1fr 1fr',gap:10,marginTop:14}}>
          <input value={pncpCnpj} onChange={e=>setPncpCnpj(e.target.value)} placeholder="CNPJ do fornecedor" style={{padding:'11px 12px',borderRadius:9,border:'1px solid var(--border-default)',background:'var(--surface-inset)',color:'var(--text-default)'}} />
          <input type="date" value={pncpFrom} onChange={e=>setPncpFrom(e.target.value)} />
          <input type="date" value={pncpTo} onChange={e=>setPncpTo(e.target.value)} />
        </div>
        {(syncSources.length>0||healthRun) && <div style={{display:'grid',gridTemplateColumns:'repeat(auto-fit,minmax(220px,1fr))',gap:10,marginTop:14}}>{syncSources.filter(s=>s.provider==='COMPRAS_GOV').map(s=><div key={s.provider} style={{padding:12,borderRadius:10,background:'var(--surface-inset)'}}><div style={{display:'flex',justifyContent:'space-between',gap:8}}><strong>Compras.gov.br · descoberta</strong><Badge tone={s.last_status==='SUCCESS'?'success':s.last_status==='PARTIAL'?'warning':s.last_status?'danger':'neutral'}>{s.last_status||'AGUARDANDO'}</Badge></div><span style={{display:'block',fontSize:12,color:'var(--text-muted)',marginTop:5}}>{s.last_run_at?'Último ciclo '+new Date(s.last_run_at).toLocaleString('pt-BR'):'Ainda não executado'}{s.last_status==='PARTIAL'?' · ciclo limitado, continua no próximo':''}</span>{s.last_error&&<span style={{display:'block',fontSize:11,color:'var(--status-warning)',marginTop:5}}>{s.last_error}</span>}</div>)}{healthRun&&<div style={{padding:12,borderRadius:10,background:'var(--surface-inset)'}}><div style={{display:'flex',justifyContent:'space-between',gap:8}}><strong>PNCP · verificação de saúde</strong><Badge tone={healthRun.status==='SUCCESS'?'success':'warning'}>{healthRun.status==='SUCCESS'?'OK':healthRun.status}</Badge></div><span style={{display:'block',fontSize:12,color:'var(--text-muted)',marginTop:5}}>Última verificação {new Date(healthRun.started_at).toLocaleString('pt-BR')}</span></div>}</div>}{pncpSummary && <div style={{display:'grid',gap:8,marginTop:12}}>{promoLabel(pncpSummary.enrichment) && <div><Badge tone={promoLabel(pncpSummary.enrichment)[1]}>{promoLabel(pncpSummary.enrichment)[0]}</Badge>{pncpSummary.enrichment.priorityScore!=null && <span style={{fontSize:12,color:'var(--text-muted)',marginLeft:8}}>Priority Score {pncpSummary.enrichment.priorityScore}</span>}</div>}{(pncpSummary.persisted||[]).slice(0,10).map((p,i)=><div key={i} style={{fontSize:12,display:'flex',gap:8,alignItems:'center',flexWrap:'wrap'}}><Badge tone={evidenceLabel(p)[1]}>{evidenceLabel(p)[0]}</Badge><span style={{color:'var(--text-muted)'}}>{p.procurementId} · publicação {p.dates?.procurementPublishedAt||'—'} · resultado {p.dates?.resultAt||'—'}</span></div>)}</div>}{pncpResult && <pre style={{margin:0,padding:12,borderRadius:10,background:'var(--surface-inset)',fontSize:11,whiteSpace:'pre-wrap',overflow:'auto'}}>{pncpResult}</pre>}
      </Card>
      <div style={cxGrid(300)}>
        {integrations.map(r => (
          <Card key={r.id} variant="card" padding={24} gap={16} interactive onClick={() => setOpen(r.id)} style={{ cursor: 'pointer' }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}><span style={{ width: 44, height: 44, borderRadius: 12, background: 'var(--overlay-05)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><i className={'ph ' + r.icon} style={{ fontSize: 22, color: 'var(--text-accent)' }} /></span><Badge tone={r.tone}>{r.status}</Badge></div>
            <span style={{ display: 'flex', flexDirection: 'column', gap: 4 }}><strong style={{ fontSize: 16 }}>{r.name}</strong><span style={{ fontSize: 13, color: 'var(--text-muted)' }}>{r.desc}</span></span>
            <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, fontSize: 12, color: 'var(--text-subtle)', borderTop: '1px solid var(--border-subtle)', paddingTop: 12 }}><span>Sync {r.sync}</span><span style={{ color: r.tone === 'warning' ? VX_TONE.warning : undefined, textAlign: 'right' }}>{r.health}</span></div>
          </Card>
        ))}
      </div>
      {it && (
        <Drawer kicker="Integração" title={it.name} subtitle={it.desc} width={480} onClose={() => setOpen(null)} footer={it.status === 'Planejada'
          ? <SoonBtn block>Configurar</SoonBtn>
          : <><SoonBtn block>{it.tone === 'neutral' ? 'Configurar' : 'Editar configuração'}</SoonBtn>{it.tone !== 'neutral' && <SoonBtn variant="danger">Desconectar</SoonBtn>}</>}>
          <div style={cxGrid(180, 20)}><DataField label="Status"><Badge tone={it.tone}>{it.status}</Badge></DataField><DataField label="Última sincronização" mono>{it.sync}</DataField><DataField label="Saúde">{it.health}</DataField><DataField label="Permissão necessária" mono>integrations.manage</DataField></div>
          <span style={vxEyebrow}>LOGS RECENTES</span>
          {it.tone === 'neutral' || !logs.length
            ? <EmptyState>{it.tone === 'neutral' ? 'Sem execuções. Configure a integração para iniciar.' : 'Sem registros de execução disponíveis para esta integração.'}</EmptyState>
            : <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>{logs.map(([id, t, tn, m]) => <div key={id} style={{ display: 'flex', gap: 12, alignItems: 'center', padding: '10px 12px', background: 'var(--surface-inset)', borderRadius: 10, fontSize: 13 }}><span style={{ ...cxMono, color: 'var(--text-subtle)' }}>{t}</span><StatusDot tone={tn} />{m}</div>)}</div>}
          <Alert tone="info">Credenciais e segredos são gerenciados no servidor. A interface nunca os exibe.</Alert>
        </Drawer>
      )}
    </BlockGrid.Auto>
  );
}
window.IntegrationsScreen = IntegrationsScreen;
