// js/components/widgets/Receber.jsx
// Contas a receber — CRUD + marcar como recebido.
// Movido de index.html em Fase 5 do refactor (2026-04-29): L6946-L7027
// Deps runtime: Modal, Icon, StatusBadge, SmartSelect, showConfirm, fmt, fmtDate, isOverdue,
//               dualWrite, genIdUUID (globals)
(function() {
  'use strict';
  const {useState, useEffect, useRef, useCallback, useMemo} = React;

function Receber({receivables,setReceivables,clients}){
  const[modal,setModal]=useState(false);
  const[form,setForm]=useState({description:'',clientId:'',value:0,due:'',status:'Pendente'});
  // [AUDM 20260511] regra_loading_state_obrigatorio — P0-4 auditoria mestra
  const savingRef=useRef(false);
  useEffect(()=>{savingRef.current=false;},[modal]);
  const markRcvInflightRef=useRef(new Set());
  const[markRcvVer,setMarkRcvVer]=useState(0);

  async function save(){
    if(savingRef.current)return;
    savingRef.current=true;
    if(!await znxGuard(['admin','financeiro'])){savingRef.current=false;return;}
    const isNew=modal!=='edit';
    const id=isNew?genIdUUID():form.id;
    const val=Number(form.value);
    const cliId=form.clientId?form.clientId:null;
    try {
      // [BUG-FIX 20260504] dualWrite — antes só setReceivables local, recebível fantasma após F5
      const ok=await dualWrite('receivables',id,
        {description:form.description||null,value:val,due:form.due||null,
         status:form.status||'Pendente',client_id:cliId},
        isNew,()=>{
          if(isNew)setReceivables(prev=>[...prev,{...form,id,value:val,clientId:cliId}]);
          else setReceivables(prev=>prev.map(r=>r.id===id?{...form,id,value:val,clientId:cliId}:r));
        });
      if(!ok){savingRef.current=false;return;}
      setModal(false); // useEffect[modal] reseta savingRef
    } catch(e) {
      savingRef.current=false;
      const msg=e.message||'Erro inesperado. Tente novamente.';
      toast('❌ '+msg);
      if(typeof Sentry!=='undefined')Sentry.captureException(e,{extra:{context:'save_receber',errorMessage:e.message,receivableId:id}});
    }
  }

  async function markReceived(id){
    if(markRcvInflightRef.current.has(id))return;
    markRcvInflightRef.current.add(id);
    setMarkRcvVer(v=>v+1);
    if(!await znxGuard(['admin','financeiro'])){
      markRcvInflightRef.current.delete(id);
      setMarkRcvVer(v=>v+1);
      return;
    }
    try {
      // [BUG-FIX 20260504] dualWrite — antes só setReceivables local, status voltava após F5
      // [FIX 20260505 sistema 4 onda 0] status='Pago' (não 'Recebido') — naming consistente
      // com banco. paid_at é populado automaticamente pelo trigger trg_receivables_auto_paid_at,
      // mas envio explícito por defesa em profundidade.
      const ok=await dualWrite('receivables',id,{status:'Pago',paid_at:new Date().toISOString()},false,()=>{
        setReceivables(prev=>prev.map(r=>r.id===id?{...r,status:'Pago',paid_at:new Date().toISOString()}:r));
      });
      if(!ok&&typeof Sentry!=='undefined'){
        Sentry.captureException(new Error('markReceived dualWrite failed'),{extra:{receivableId:id}});
      }
    } catch(e) {
      const msg=e.message||'Erro inesperado. Tente novamente.';
      toast('❌ '+msg);
      if(typeof Sentry!=='undefined')Sentry.captureException(e,{extra:{context:'markReceived_receber',errorMessage:e.message,receivableId:id}});
    } finally {
      markRcvInflightRef.current.delete(id);
      setMarkRcvVer(v=>v+1);
    }
  }

  const pending=receivables.filter(r=>r.status==='Pendente');
  const totalPending=pending.reduce((s,r)=>s+r.value,0);
  const overdue=pending.filter(r=>isOverdue(r.due));

  return(
    <div>
      <div className="page-header">
        <div className="page-title">Contas a Receber</div>
        <button className="btn-gold" onClick={()=>{setForm({description:'',clientId:clients[0]?.id||'',value:0,due:'',status:'Pendente'});setModal('new')}} style={{display:'flex',alignItems:'center',gap:6}}><Icon n="plus" size={14}/>Nova Conta</button>
      </div>
      <div style={{display:'grid',gridTemplateColumns:'repeat(3,1fr)',gap:16,marginBottom:20}}>
        <div className="stat-card"><div className="stat-label">Total a Receber</div><div className="stat-value">{fmt(totalPending)}</div></div>
        <div className="stat-card"><div className="stat-label">Em Atraso</div><div className="stat-value" style={{color:'#DC2626'}}>{overdue.length}</div></div>
        <div className="stat-card"><div className="stat-label">Recebido (Mês)</div><div className="stat-value" style={{color:'#16A34A'}}>{fmt(receivables.filter(r=>{
          if(r.status!=='Pago')return false;
          // [ONDA3 P2 2026-05-11] fallback explícito do paid_at — origem dos dados:
          //   1) r.paid_at: coluna canônica preenchida quando recebimento é confirmado
          //   2) r.paidAt: alias camelCase usado por triggers JSONB sync_jsonb_receivables
          //   3) r.updated_at: fallback caso paid_at fique NULL em registro legacy (pré-trigger)
          //   4) r.due: último recurso — pelo menos garante conta no mês de vencimento
          const paidAt = r.paid_at || r.paidAt || r.updated_at || r.due || '';
          return paidAt.slice(0,7) === today().slice(0,7);
        }).reduce((s,r)=>s+r.value,0))}</div></div>
      </div>
      {overdue.map(r=><div key={r.id} className="alert-danger" style={{marginBottom:8,fontSize:13}}>{r.description} — Venceu {fmtDate(r.due)} — {fmt(r.value)}</div>)}
      <div className="card" style={{padding:0}}>
        <table>
          <thead><tr><th>Descrição</th><th>Cliente</th><th>Valor</th><th>Vencimento</th><th>Status</th><th>Ações</th></tr></thead>
          <tbody>
            {receivables.map(r=>{
              const c=clients.find(x=>x.id===r.clientId);
              const over=r.status==='Pendente'&&isOverdue(r.due);
              return(
                <tr key={r.id}>
                  <td>{r.description}</td>
                  <td className="dim">{c?.name||'—'}</td>
                  <td className="gold">{fmt(r.value)}</td>
                  <td style={{color:over?'#DC2626':isDueToday(r.due)?'#2563EB':'inherit'}}>{fmtDate(r.due)}{over?' ⚠':''}</td>
                  <td><StatusBadge status={r.status}/></td>
                  <td>
                    <div style={{display:'flex',gap:6}}>
                      {r.status==='Pendente'&&<button className="btn-gold btn-sm" disabled={markRcvInflightRef.current.has(r.id)} onClick={()=>markReceived(r.id)}>{markRcvInflightRef.current.has(r.id)?'…':'Receber'}</button>}
                      <button className="btn-outline btn-sm" onClick={()=>{setForm(r);setModal('edit')}}><Icon n="edit" size={12}/></button>
                    </div>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      {modal&&(
        <Modal title={modal==='edit'?'Editar Conta':'Nova Conta a Receber'} onClose={()=>setModal(false)}>
          <div className="form-grid">
            <div className="form-group full"><label>Descrição</label><input value={form.description} onChange={e=>setForm(f=>({...f,description:e.target.value}))}/></div>
            <div className="form-group"><label>Cliente</label>
              <SmartSelect value={form.clientId||''} onChange={val=>setForm(f=>({...f,clientId:val}))} options={[{value:'',label:'— Avulso —'},...clients.filter(c=>!(window.znxIsClientBlocked&&window.znxIsClientBlocked(c))).map(c=>({value:c.id,label:c.name}))]}/>

            </div>
            <div className="form-group"><label>Vencimento</label><input type="date" value={form.due} onChange={e=>setForm(f=>({...f,due:e.target.value}))}/></div>
            <div className="form-group"><label>Valor (R$)</label><input type="number" value={form.value} onChange={e=>setForm(f=>({...f,value:e.target.value}))}/></div>
            <div className="form-group"><label>Status</label>
              <SmartSelect value={form.status} onChange={val=>setForm(f=>({...f,status:val}))} options={[{value:'Pendente',label:'Pendente'},{value:'Pago',label:'Recebido'}]}/>
            </div>
          </div>
          <div style={{display:'flex',gap:10,marginTop:20,justifyContent:'flex-end'}}>
            <button className="btn-outline" onClick={()=>setModal(false)}>Cancelar</button>
            <button className="btn-gold" disabled={savingRef.current} onClick={save}>{savingRef.current?'Salvando…':'Salvar'}</button>
          </div>
        </Modal>
      )}
    </div>
  );
}

// ══════════════════════════════════════════════════════════════
// RELATÓRIO
// ══════════════════════════════════════════════════════════════

  window.ZNX = window.ZNX || {};
  window.ZNX.components = window.ZNX.components || {};
  window.ZNX.components.Receber = Receber;
  window.Receber = Receber;

  window.ZNX.refactor_phase_5_loaded = window.ZNX.refactor_phase_5_loaded || {};
  window.ZNX.refactor_phase_5_loaded.Receber = true;

})();
