// js/components/pages/DashboardV2.jsx
// Dashboard executivo redesenhado — ONDA H 2026-05-07.
// 4 seções: HOJE compacto | MÊS com meta global | 3 cards (Atividade WA + Alertas + Top vendedoras) | Gráfico SVG 14d.
// Removida duplicação com outras páginas (Vendas, Orcamentos, Clientes, Usuários, ComissaoAdmin).
// VendedorActivityCard movido pra UsersPanel.jsx.
//
// Props: user, data, metas, setMetas, metasBase, setMetasBase, metasEmpresa, setMetasEmpresa,
//        allUsers, extraUsers, setExtraUsers, discountRequests, cancelRequests, onOpenDiscountModal, onOpenCancelModal
//
// Deps runtime: fmt, fmtDate, today, saleFinalTotal, saleProfit, isFaturada, isLowStock, isOverdue, isDueToday, Modal, ApprovalHub, ComissaoAdmin
(function() {
  'use strict';
  const {useState, useMemo, useEffect} = React;

function DashboardV2(props){
  const {user,data,metas,metasBase={},allUsers,metasEmpresa={},setMetasEmpresa,discountRequests=[],cancelRequests=[]} = props;
  // [Bug #642 fase 2 20260518] `gastos` extraído do `data` — fonte real de despesas (alinhado Bug #619).
  // App.jsx L1101 agora inclui gastos no data object. Sem gastos → fallback BRUTO (back-compat).
  // [HOTFIX v223.42.2 20260520] ZAYNEX-ERP-4P defensive coalesce — data pode vir parcialmente undefined
  // durante Realtime hot-swap. .filter is not a function crash → ErrorBoundary loop infinito boot.
  const {products=[],sales=[],quotes=[],payables=[],receivables=[],clients=[],gastos=[]} = (data || {});
  // [Wave 12A v223.34] state editMetaEmpresaModal+editMetaValor extracted to MonthMetaCard.jsx

  const todayStr = today();
  const currentMonth = todayStr.slice(0,7); // YYYY-MM
  const yesterdayStr = (()=>{ const d=new Date(); d.setDate(d.getDate()-1); return d.toISOString().slice(0,10); })();

  // ─── DATASETS ───
  const mySales = (user.role==='vendedor'?sales.filter(s=>s.sellerName===user.name):sales).filter(isFaturada);
  const monthSales = mySales.filter(s=>s.date?.startsWith(currentMonth));
  const todaySales = mySales.filter(s=>s.date===todayStr);
  const yesterdaySales = mySales.filter(s=>s.date===yesterdayStr);
  // Últimos 7 dias (excluindo hoje pra média)
  const last7Days = useMemo(()=>{
    const arr=[];
    for(let i=1;i<=7;i++){
      const d=new Date(); d.setDate(d.getDate()-i);
      arr.push(d.toISOString().slice(0,10));
    }
    return arr;
  },[todayStr]);
  const last7DaysSales = mySales.filter(s=>last7Days.includes(s.date));

  // ─── KPIs HOJE ───
  const todayRevenue = todaySales.reduce((a,s)=>a+saleFinalTotal(s),0);
  // [Hotfix v223.13 20260518] Lucro Bruto via factory unificada cross-page.
  // ANTES: saleProfit puro (não deduzia globalDiscount). Causava DashboardV2 R$ 230k vs Relatorio R$ 211k.
  // AGORA: computeLucroBrutoPeriodo (lib/relatorio/calcs.js) — mesma fórmula 3 pages.
  // Fallback saleProfit defensive se factory não carregar.
  const _calcLB = window.ZNX?.relatorio?.calcs?.computeLucroBrutoPeriodo;
  const todayProfit = _calcLB
    ? _calcLB(todaySales, products)
    : todaySales.reduce((a,s)=>a+saleProfit(s.items,products),0); // fallback BRUTO simples
  const todayMargin = todayRevenue>0 ? (todayProfit/todayRevenue*100) : 0; // BRUTA
  // [Bug #642 fase 2 20260518] Lucro Líquido HOJE = Bruto − Gastos do dia (Pago+Parcial, status válido).
  // Mesma fonte real Bug #619 (computeGastosMes pattern). Consistente cross-page.
  const todayGastos = (gastos||[]).reduce((a,g)=>{
    if(g.deleted_at) return a;
    if(g.status!=='Pago' && g.status!=='Parcial') return a;
    if(String(g.date||'')!==todayStr) return a;
    return a + (Number(g.value)||0);
  },0);
  const todayLucroLiquido = todayProfit - todayGastos;
  const todayMarginLiquida = todayRevenue>0 ? (todayLucroLiquido/todayRevenue*100) : 0;
  const yesterdayRevenue = yesterdaySales.reduce((a,s)=>a+saleFinalTotal(s),0);
  const last7Revenue = last7DaysSales.reduce((a,s)=>a+saleFinalTotal(s),0);
  const last7Avg = last7DaysSales.length>0 ? last7Revenue/7 : 0;

  // [Wave 12A v223.34] deltaPct/deltaColor extracted (inline) to TodayHero.jsx — dead code removed here

  // ─── KPIs MÊS ───
  const monthRevenue = monthSales.reduce((a,s)=>a+saleFinalTotal(s),0);
  // [Hotfix v223.13] Mês via mesma factory unificada (regra_no_paralelo — single source).
  const monthProfit = _calcLB
    ? _calcLB(monthSales, products)
    : monthSales.reduce((a,s)=>a+saleProfit(s.items,products),0); // fallback BRUTO simples
  const monthMargin = monthRevenue>0 ? (monthProfit/monthRevenue*100) : 0; // BRUTA
  // [Bug #642 fase 2 20260518] Lucro Líquido MÊS = Bruto − Gastos do mês (Pago+Parcial).
  // Mesma fonte real Bug #619 (factory computeGastosMes — single-source-of-truth cross-page).
  const monthGastos = (gastos||[]).reduce((a,g)=>{
    if(g.deleted_at) return a;
    if(g.status!=='Pago' && g.status!=='Parcial') return a;
    if(!(String(g.date||'').startsWith(currentMonth))) return a;
    return a + (Number(g.value)||0);
  },0);
  const monthLucroLiquido = monthProfit - monthGastos;
  const monthMarginLiquida = monthRevenue>0 ? (monthLucroLiquido/monthRevenue*100) : 0;
  const metaEmpresaAtual = Number(metasEmpresa?.[currentMonth]) || 0;
  const pctMetaEmpresa = metaEmpresaAtual>0 ? Math.min(100,(monthRevenue/metaEmpresaAtual)*100) : 0;
  const faltaMetaEmpresa = Math.max(0, metaEmpresaAtual - monthRevenue);
  const now=new Date();
  const diasNoMes=new Date(now.getFullYear(),now.getMonth()+1,0).getDate();
  const diasRestantes=Math.max(0, diasNoMes-now.getDate());
  const precisaPorDia = diasRestantes>0 && faltaMetaEmpresa>0 ? faltaMetaEmpresa/diasRestantes : 0;
  const metaCor = pctMetaEmpresa>=100?'#16A34A':pctMetaEmpresa>=95?'#22C55E':pctMetaEmpresa>=80?'#2563EB':pctMetaEmpresa>=60?'#EAB308':pctMetaEmpresa>=40?'#EA580C':pctMetaEmpresa>=20?'#DC2626':'#991B1B';

  // ─── TOP 3 VENDEDORAS DO MÊS ───
  const topVendedoras = useMemo(()=>{
    const byVend = {};
    monthSales.forEach(s=>{
      const name = s.sellerName || '—';
      if(!byVend[name]) byVend[name] = {name, total:0, count:0};
      byVend[name].total += saleFinalTotal(s);
      byVend[name].count++;
    });
    return Object.values(byVend).filter(v=>v.name!=='—').sort((a,b)=>b.total-a.total).slice(0,3);
  },[monthSales]);

  // ─── ALERTAS ───
  const noStock = products.filter(p=>p.stock<=0 && !p.isDecant);
  const acabando = products.filter(p=>p.stock>0 && p.stock<=(p.estoqueMin||20) && !p.isDecant);
  const overduePay = payables.filter(p=>p.status==='Pendente' && isOverdue(p.due));
  const overdueRec = receivables.filter(r=>r.status==='Pendente' && isOverdue(r.due));
  const pendingApprovals = (discountRequests||[]).filter(d=>d.status==='pending').length + (cancelRequests||[]).filter(c=>c.status==='pending').length;

  // ─── [ONDA H+] ANIVERSARIANTES da semana — filtrado por vendedora se role=vendedor ───
  // [Wave 12B v223.35] state showAllBirthdays extracted to AniversariantesCard.jsx
  const aniversariantes = useMemo(()=>{
    const tWeek = new Date(); tWeek.setDate(tWeek.getDate()+7);
    const t0 = new Date(); t0.setHours(0,0,0,0);
    const isInWeek = (bd) => {
      if(!bd) return false;
      const [y,m,d] = String(bd).split('-');
      if(!m||!d) return false;
      const thisYear = new Date(t0.getFullYear(),Number(m)-1,Number(d));
      // Se aniversário esse ano já passou, considera próximo ano
      if(thisYear < t0) thisYear.setFullYear(thisYear.getFullYear()+1);
      return thisYear >= t0 && thisYear <= tWeek;
    };
    let candidates = (clients||[]).filter(c=>c.birth_date && isInWeek(c.birth_date));
    // Se vendedor: filtra só clientes que ele vendeu
    if(user.role === 'vendedor'){
      const myClientIds = new Set(mySales.map(s=>s.client_id || s.clientId).filter(Boolean));
      candidates = candidates.filter(c=>myClientIds.has(c.id));
    }
    // Ordena por data mais próxima
    return candidates.map(c=>{
      const [y,m,d] = String(c.birth_date).split('-');
      const thisYear = new Date(t0.getFullYear(),Number(m)-1,Number(d));
      if(thisYear < t0) thisYear.setFullYear(thisYear.getFullYear()+1);
      const daysUntil = Math.floor((thisYear - t0)/86400000);
      return {...c, daysUntil, birthdayLabel: `${d}/${m}`};
    }).sort((a,b)=>a.daysUntil-b.daysUntil);
  },[clients, user.role, user.name, mySales]);

  // ─── [ONDA H+] CASH FLOW próximos 30 dias ───
  const cashFlow30d = useMemo(()=>{
    const now = new Date();
    const future = new Date(); future.setDate(future.getDate()+30);
    const isInRange = (dueStr) => {
      if(!dueStr) return false;
      const due = new Date(dueStr);
      return due >= now && due <= future;
    };
    const aReceber = (receivables||[]).filter(r=>r.status==='Pendente' && isInRange(r.due)).reduce((a,r)=>a+Number(r.value||0),0);
    const aPagar = (payables||[]).filter(p=>p.status==='Pendente' && isInRange(p.due)).reduce((a,p)=>a+Number(p.value||0),0);
    const saldo = aReceber - aPagar;
    const qtdReceber = (receivables||[]).filter(r=>r.status==='Pendente' && isInRange(r.due)).length;
    const qtdPagar = (payables||[]).filter(p=>p.status==='Pendente' && isInRange(p.due)).length;
    return {aReceber, aPagar, saldo, qtdReceber, qtdPagar};
  },[receivables, payables]);

  // ─── [ONDA H+] PRODUTOS QUE VÃO ZERAR em 7 dias ───
  // [Wave 12B v223.35] state showStockModal extracted to EstoqueSaudeCard.jsx
  const projecaoZerar = useMemo(()=>{
    // Calcula vendas média 30d por produto
    const t30 = new Date(); t30.setDate(t30.getDate()-30);
    const recent = sales.filter(s=>new Date(s.date||s.createdAt) >= t30 && s.status!=='Cancelada' && s.status!=='Cancelado');
    const dailyAvgByProduct = {};
    recent.forEach(s=>{
      (s.items||[]).forEach(it=>{
        const pid = it.productId || it.product_id;
        if(!pid) return;
        dailyAvgByProduct[pid] = (dailyAvgByProduct[pid]||0) + Number(it.qty||0);
      });
    });
    Object.keys(dailyAvgByProduct).forEach(k=>{ dailyAvgByProduct[k] = dailyAvgByProduct[k]/30; });
    return products.filter(p=>{
      if(p.stock<=0 || p.isDecant) return false;
      const avg = dailyAvgByProduct[p.id] || 0;
      if(avg < 0.3) return false; // ignora produtos com vendas insignificantes
      const diasRestantes = p.stock / avg;
      return diasRestantes <= 7;
    }).map(p=>{
      const avg = dailyAvgByProduct[p.id] || 0;
      const dias = avg>0 ? Math.floor(p.stock/avg) : 0;
      return {...p, dailyAvg:avg, diasRestantes:dias};
    }).sort((a,b)=>a.diasRestantes-b.diasRestantes).slice(0,10);
  },[products, sales]);

  // ─── [ONDA H+] TOP 3 PRODUTOS DA SEMANA ───
  const topProdutosSemana = useMemo(()=>{
    const t7 = new Date(); t7.setDate(t7.getDate()-7);
    const semana = sales.filter(s=>new Date(s.date||s.createdAt) >= t7 && s.status!=='Cancelada' && s.status!=='Cancelado');
    const byProd = {};
    semana.forEach(s=>{
      (s.items||[]).forEach(it=>{
        const pid = it.productId || it.product_id;
        if(!pid) return;
        if(!byProd[pid]){
          const p = products.find(pp=>pp.id===pid);
          byProd[pid] = {id:pid, name: p?.name || it.productName || it.product_name || 'Produto', qty:0, total:0};
        }
        byProd[pid].qty += Number(it.qty||0);
        byProd[pid].total += Number(it.qty||0) * Number(it.price||0);
      });
    });
    return Object.values(byProd).sort((a,b)=>b.qty-a.qty).slice(0,3);
  },[products, sales]);

  // ─── ATIVIDADE EQUIPE (resumo, full em Usuários) ───
  // Fica curto aqui — detalhes em Usuários
  const [outreachStats,setOutreachStats] = useState({total:0, conversoes:0, top:null});
  useEffect(()=>{
    if(user.role!=='admin' && user.role!=='financeiro') return;
    const sevenDaysAgo = new Date(); sevenDaysAgo.setDate(sevenDaysAgo.getDate()-7);
    sb.from('client_outreach').select('vendedora_name,client_id').gte('sent_at',sevenDaysAgo.toISOString())
      .then(({data})=>{
        if(!data) return;
        const byVend={};
        data.forEach(o=>{ byVend[o.vendedora_name]=(byVend[o.vendedora_name]||0)+1; });
        const top=Object.entries(byVend).sort((a,b)=>b[1]-a[1])[0];
        setOutreachStats({
          total: data.length,
          conversoes: 0, // simplificado — full em Usuários
          top: top ? {name:top[0], count:top[1]} : null
        });
      })
      .catch(e=>znxLogWarn('[ZNX] dashboard outreach load fail', e));
  },[user.role]);

  // ─── [v223.18 UX] GRÁFICO MÊS INTEIRO (D1-D31) + overlay mês anterior ───
  // Substitui chart14 (rolling 14d arbitrário) por mês corrente. Alinha com
  // fechamento mensal (meta empresa, comissão 1%/0.5%, DRE). Opção B Jamal: ghost futuro.
  const chartMes = useMemo(()=>{
    const buckets=[];
    const now = new Date();
    const ano = now.getFullYear();
    const mes = now.getMonth(); // 0-11
    const hoje = now.getDate();
    const ultimoDia = new Date(ano, mes+1, 0).getDate(); // 28/29/30/31
    for(let dia=1; dia<=ultimoDia; dia++){
      const d = new Date(ano, mes, dia);
      const dStr = d.toISOString().slice(0,10);
      const isFuture = dia > hoje;
      const dailyTotal = isFuture ? 0 : mySales.filter(s=>s.date===dStr).reduce((a,s)=>a+saleFinalTotal(s),0);
      // Mesmo dia mês anterior pra overlay (mês inteiro)
      const dPrev = new Date(ano, mes-1, dia);
      const dPrevStr = dPrev.toISOString().slice(0,10);
      const prevTotal = mySales.filter(s=>s.date===dPrevStr).reduce((a,s)=>a+saleFinalTotal(s),0);
      buckets.push({date:dStr, total:dailyTotal, totalPrev:prevTotal, label:String(dia), isFuture, dia});
    }
    return buckets;
  },[mySales]);
  // chartMax/Pico ignoram futuros (senão pico fica em 0)
  const chartMesRealizado = chartMes.filter(b => !b.isFuture);
  const chartMax = Math.max(...chartMes.map(b=>Math.max(b.total,b.totalPrev||0)), 1);
  const chartHoje = chartMesRealizado[chartMesRealizado.length-1] || chartMes[0];
  const chartPico = chartMesRealizado.reduce((max,b)=>b.total>max.total?b:max, chartMesRealizado[0] || chartMes[0]);
  // Label do mês pra header (ex: "MAIO 2026")
  const chartMesLabel = (() => {
    const meses = ['JANEIRO','FEVEREIRO','MARÇO','ABRIL','MAIO','JUNHO','JULHO','AGOSTO','SETEMBRO','OUTUBRO','NOVEMBRO','DEZEMBRO'];
    const now = new Date();
    return `${meses[now.getMonth()]} ${now.getFullYear()}`;
  })();
  const chartHojeDia = new Date().getDate();
  const chartUltimoDia = new Date(new Date().getFullYear(), new Date().getMonth()+1, 0).getDate();

  // [Wave 12A v223.34] openMetaEmpresaModal/saveMetaEmpresa extracted to MonthMetaCard.jsx

  // ─── RENDER ───
  return(
    <div className="page-content" style={{display:'flex',flexDirection:'column',gap:14}}>

      {/* Boas-vindas */}
      <div style={{padding:'14px 18px',background:'linear-gradient(135deg,#FEF3C7,#FFFBEB)',border:'1px solid #C8A95133',borderRadius:12}}>
        <div style={{fontSize:11,color:'#92700A',fontWeight:600,textTransform:'uppercase',letterSpacing:1}}>Bem-vindo de volta,</div>
        <div style={{fontSize:22,fontWeight:800,color:'#1B2A4A',marginTop:2}}>{user.name||user.username} 💪</div>
      </div>

      {/* ═══ SEÇÃO 1 — HOJE [Wave 12A v223.34 extracted to TodayHero.jsx] ═══ */}
      <TodayHero
        todayRevenue={todayRevenue}
        todayProfit={todayProfit}
        todayMargin={todayMargin}
        todayLucroLiquido={todayLucroLiquido}
        todayMarginLiquida={todayMarginLiquida}
        todayGastos={todayGastos}
        todaySales={todaySales}
        yesterdayRevenue={yesterdayRevenue}
        last7Avg={last7Avg}
      />

      {/* ═══ SEÇÃO 2 — ESTE MÊS COM META GLOBAL [Wave 12A v223.34 extracted to MonthMetaCard.jsx] ═══ */}
      <MonthMetaCard
        user={user}
        currentMonth={currentMonth}
        monthRevenue={monthRevenue}
        monthProfit={monthProfit}
        monthMargin={monthMargin}
        monthLucroLiquido={monthLucroLiquido}
        monthMarginLiquida={monthMarginLiquida}
        monthGastos={monthGastos}
        monthSales={monthSales}
        metasEmpresa={metasEmpresa}
        setMetasEmpresa={setMetasEmpresa}
        metas={metas}
      />

      {/* [V4 ADMIN FIX 20260518 v223.16] ComissaoAdmin operacional — botão Fechar Mês + Marcar Paga + 4 stats cards + tabela vendedoras.
          Antes desta linha, componente existia (widgets/ComissaoAdmin.jsx 292L) mas NÃO era renderizado pra admin.
          Routing App.jsx L1159: admin → DashboardV2 (não Dashboard original onde widget JÁ renderizava L297).
          Guard admin/financeiro: vendedora vê widget próprio em Dashboard.jsx; ComissaoAdmin tem znxGuard interno tb. */}
      {(user.role==='admin'||user.role==='financeiro') && (
        <div style={{marginTop:20,marginBottom:8}}>
          <ComissaoAdmin user={user} allUsers={allUsers}/>
        </div>
      )}

      {/* ═══ SEÇÃO 3 — 3 CARDS (Atividade resumo, Alertas, Top vendedoras) ═══ */}
      <div style={{display:'grid',gridTemplateColumns:'repeat(auto-fit,minmax(280px,1fr))',gap:12}}>

        {/* Atividade resumida */}
        {(user.role==='admin'||user.role==='financeiro') && (
          <div className="card" style={{padding:14}}>
            <div style={{fontSize:11,color:'#9CA3AF',fontWeight:700,textTransform:'uppercase',letterSpacing:1.2,marginBottom:8}}>
              📊 Atividade Equipe (7d)
            </div>
            <div style={{fontSize:24,fontWeight:800,color:'#2563EB'}}>{outreachStats.total}</div>
            <div style={{fontSize:11,color:'#6B7280'}}>disparos WhatsApp</div>
            {outreachStats.top && (
              <div style={{marginTop:10,padding:'6px 10px',background:'#EEF2FF',borderRadius:6,fontSize:11,color:'#3730A3'}}>
                Top: <strong>{outreachStats.top.name}</strong> ({outreachStats.top.count})
              </div>
            )}
            <div style={{fontSize:10,color:'#9CA3AF',marginTop:8,fontStyle:'italic'}}>Detalhes completos em Usuários</div>
          </div>
        )}

        {/* Alertas [Wave 12A v223.34 extracted to AlertasCard.jsx] */}
        <AlertasCard
          overduePay={overduePay}
          overdueRec={overdueRec}
          noStock={noStock}
          acabando={acabando}
          pendingApprovals={pendingApprovals}
        />

        {/* Top vendedoras [Wave 12A v223.34 extracted to TopVendedorasCard.jsx] */}
        {(user.role==='admin'||user.role==='financeiro') && (
          <TopVendedorasCard topVendedoras={topVendedoras}/>
        )}
      </div>

      {/* ═══ SEÇÃO 3.5 [Wave 12B v223.35 extracted to 4 widgets: AniversariantesCard + CashFlow30dCard + EstoqueSaudeCard + TopProdutosSemanaCard] ═══ */}
      <div style={{display:'grid',gridTemplateColumns:'repeat(auto-fit,minmax(280px,1fr))',gap:12}}>
        <AniversariantesCard user={user} aniversariantes={aniversariantes} clients={clients}/>
        <CashFlow30dCard user={user} cashFlow30d={cashFlow30d}/>
        <EstoqueSaudeCard noStock={noStock} acabando={acabando} projecaoZerar={projecaoZerar}/>
        <TopProdutosSemanaCard topProdutosSemana={topProdutosSemana}/>
      </div>

      {/* ═══ SEÇÃO 4 [Wave 12B v223.35 extracted to GraficoMesView.jsx — SVG 121L denso] ═══ */}
      <GraficoMesView
        chartMes={chartMes}
        chartMax={chartMax}
        chartHoje={chartHoje}
        chartPico={chartPico}
        chartMesLabel={chartMesLabel}
        chartHojeDia={chartHojeDia}
        chartUltimoDia={chartUltimoDia}
      />

      {/* [Wave 12B v223.35] MODAL ESTOQUE extracted to EstoqueSaudeCard.jsx · MODAL ANIVERSARIANTES extracted to AniversariantesCard.jsx · MODAL Meta Empresa em MonthMetaCard.jsx (Wave 12A) */}
    </div>
  );
}

// Namespace
window.ZNX = window.ZNX || {};
window.ZNX.components = window.ZNX.components || {};
window.ZNX.components.DashboardV2 = DashboardV2;
window.DashboardV2 = DashboardV2;
})();
