const { useState, useMemo, useEffect } = React;

/* Parâmetros da demonstração: todos fictícios, a validar com a operação */
const NOW_H = 11.5; // relógio da demo: 11:30
const CUSTO_KM = 7.2; // R$ por km rodado
const VEL_MEDIA = 55; // km/h
const FATOR_ESTRADA = 1.3; // linha reta x 1,3 = estrada (aproximação)
const INTERVALO_REVISAO = 20000; // km
const VIDA_PNEU = 90000; // km
const PRECO_MEDIO = 5.6; // R$/L vendido ao posto (fictício)
const PRODUCTS = ['Diesel S10','Diesel S500','Gasolina C','Etanol'];

const cities = {
  'Barretos':[-20.557,-48.568], 'Bebedouro':[-20.949,-48.479], 'Olímpia':[-20.737,-48.915], 'Colina':[-20.713,-48.541],
  'Guaíra':[-20.318,-48.311], 'Monte Azul Paulista':[-20.907,-48.641], 'Severínia':[-20.809,-48.806], 'Terra Roxa':[-20.787,-48.331],
  'Altair':[-20.524,-49.057], 'Colômbia':[-20.176,-48.689], 'Jaborandi':[-20.688,-48.411], 'Viradouro':[-20.873,-48.297],
  'Ribeirão Preto':[-21.177,-47.810],
};

function dist(a,b){
  if(a===b) return 0;
  const [la1,lo1]=cities[a],[la2,lo2]=cities[b]; const r=Math.PI/180;
  const h=Math.sin((la2-la1)*r/2)**2+Math.cos(la1*r)*Math.cos(la2*r)*Math.sin((lo2-lo1)*r/2)**2;
  return Math.round(2*6371*Math.asin(Math.sqrt(h))*FATOR_ESTRADA);
}
function routeFrom(start,stops){
  let cur=start,left=[...new Set(stops)],seq=[],km=0;
  while(left.length){ left.sort((x,y)=>dist(cur,x)-dist(cur,y)); const nx=left.shift(); km+=dist(cur,nx); seq.push(nx); cur=nx; }
  return {seq,km,end:cur};
}
const fmt=(v)=>new Intl.NumberFormat('pt-BR').format(v);
const brl=(v)=>'R$ '+new Intl.NumberFormat('pt-BR',{maximumFractionDigits:0}).format(Math.round(v));
const brl2=(v)=>'R$ '+v.toFixed(2).replace('.',',');
const brl3=(v)=>'R$ '+v.toFixed(3).replace('.',',');
const mi=(v)=>(v/1e6).toFixed(2).replace('.',',')+' mi';
const clamp=(v)=>Math.max(0,Math.min(100,v));
const clock=(h)=>{ const t=Math.round((NOW_H+h)*60); const d=Math.floor(t/1440); const m=t%1440; const s=`${String(Math.floor(m/60)).padStart(2,'0')}:${String(m%60).padStart(2,'0')}`; return d>0?`amanhã ${s}`:s; };
const hrs=(h)=>{ const m=Math.round(h*60); return m<60?`${m} min`:`${Math.floor(m/60)}h${String(m%60).padStart(2,'0')}`; };
const addDays=(n)=>{ const d=new Date(2026,8,21); d.setDate(d.getDate()+n); return d.toLocaleDateString('pt-BR'); };
const newId=(p)=>p+'-'+Math.random().toString(36).slice(2,7).toUpperCase();

/* Guarda cadastros no navegador de quem usa (não é banco de dados) */
const STORE='viaflux:v3:';
function usePersist(key,initial){
  const [v,setV]=useState(()=>{ try{ const s=localStorage.getItem(STORE+key); return s?JSON.parse(s):initial; }catch(e){ return initial; } });
  useEffect(()=>{ try{ localStorage.setItem(STORE+key,JSON.stringify(v)); }catch(e){} },[key,v]);
  return [v,setV];
}

const navItems = [
  { id:'dashboard', label:'Visão geral', short:'Visão', icon:'▦' },
  { id:'logistica', label:'Pedidos e viagens', short:'Viagens', icon:'◆' },
  { id:'clientes', label:'Carteira de clientes', short:'Clientes', icon:'◉' },
  { id:'frota', label:'Frota', short:'Frota', icon:'▰' },
  { id:'mercado', label:'Mercado e cotações', short:'Mercado', icon:'◭', tag:'ao vivo' },
  { id:'relatorios', label:'Relatórios', short:'Relatórios', icon:'▥', tag:'novo' },
  { id:'cadastros', label:'Cadastros', short:'Cadastros', icon:'☰', tag:'novo' },
];

const initialBases = [
  {id:'B-01',name:'Base Barretos',city:'Barretos',kind:'Base própria',products:['Diesel S10','Diesel S500','Gasolina C','Etanol'],loadH:1,garage:true},
  {id:'B-02',name:'Terminal Ribeirão Preto',city:'Ribeirão Preto',kind:'Terminal',products:['Diesel S10','Diesel S500','Gasolina C'],loadH:1.5},
  {id:'B-03',name:'Usina Olímpia',city:'Olímpia',kind:'Usina',products:['Etanol'],loadH:0.75},
  {id:'B-04',name:'Usina Guaíra',city:'Guaíra',kind:'Usina',products:['Etanol'],loadH:0.75},
];

const initialSellers = [
  {id:'V-01',name:'Juliana Prado',region:'Barretos, Colina e Terra Roxa',meta:3500000},
  {id:'V-02',name:'Marcelo Tavares',region:'Olímpia, Altair e Severínia',meta:1700000},
  {id:'V-03',name:'Ricardo Souza',region:'Bebedouro, Guaíra e Monte Azul',meta:1400000},
];

const initialClients=[
  {id:'C-01',name:'Auto Posto Irmãos Colina',city:'Colina',sellerId:'V-01',postos:2,vol:800000,margem:0.12,carga:45000,atraso:1,compras:24,note:'Acesso fácil, recebe carreta cheia'},
  {id:'C-02',name:'Rede Horizonte',city:'Altair',sellerId:'V-02',postos:1,vol:1000000,margem:0.09,carga:15000,atraso:2,compras:34,note:'Acesso restrito: só caminhão de até 15.000 L'},
  {id:'C-03',name:'Rede Barretos',city:'Barretos',sellerId:'V-01',postos:4,vol:1600000,margem:0.08,carga:30000,atraso:6,compras:40,note:'Maior volume da carteira'},
  {id:'C-04',name:'Posto Avenida',city:'Bebedouro',sellerId:'V-03',postos:1,vol:420000,margem:0.11,carga:30000,atraso:0,compras:14,note:'Paga sempre em dia'},
  {id:'C-05',name:'Posto Imperial',city:'Olímpia',sellerId:'V-02',postos:1,vol:300000,margem:0.13,carga:15000,atraso:12,compras:10,note:'Tanques pequenos: entregas fracionadas'},
  {id:'C-06',name:'Posto Nogueira',city:'Colina',sellerId:'V-01',postos:1,vol:260000,margem:0.10,carga:20000,atraso:1,compras:9,note:''},
  {id:'C-07',name:'Posto Santa Rita',city:'Monte Azul Paulista',sellerId:'V-03',postos:1,vol:180000,margem:0.14,carga:10000,atraso:0,compras:8,note:'Pedidos pequenos e urgentes'},
  {id:'C-08',name:'Auto Posto Guaíra',city:'Guaíra',sellerId:'V-03',postos:2,vol:650000,margem:0.095,carga:30000,atraso:3,compras:20,note:''},
  {id:'C-09',name:'Posto Via Rio',city:'Severínia',sellerId:'V-02',postos:1,vol:220000,margem:0.12,carga:15000,atraso:25,compras:7,note:'Histórico de atraso no pagamento'},
  {id:'C-10',name:'Rede Terra Roxa',city:'Terra Roxa',sellerId:'V-01',postos:3,vol:900000,margem:0.085,carga:30000,atraso:4,compras:26,note:''},
];

const initialOrders = [
  {id:'#PED-2841',client:'Posto Avenida',city:'Bebedouro',volume:30000,window:'Hoje, 14:00',deadlineH:2.5,product:'Diesel S10',priority:'Alta'},
  {id:'#PED-2845',client:'Posto Santa Rita',city:'Monte Azul Paulista',volume:8000,window:'Hoje, 15:00',deadlineH:3.5,product:'Diesel S10',priority:'Alta'},
  {id:'#PED-2837',client:'Rede Barretos',city:'Barretos',volume:45000,window:'Hoje, 16:30',deadlineH:5,product:'Gasolina C',priority:'Alta'},
  {id:'#PED-2834',client:'Posto Imperial',city:'Olímpia',volume:15000,window:'Amanhã, 08:00',deadlineH:20.5,product:'Etanol',priority:'Normal'},
  {id:'#PED-2832',client:'Posto Nogueira',city:'Colina',volume:20000,window:'Amanhã, 09:30',deadlineH:22,product:'Diesel S500',priority:'Normal'},
];

const initialTrips = [
  {id:'VG-1084',truck:'TRK-04 · GHF-7D21',driver:'Rafael Moreira',route:'Barretos → Bebedouro',volume:45000,capacity:45000,status:'Em rota',eta:'12:12',orders:2},
  {id:'VG-1082',truck:'TRK-05 · EKL-3B09',driver:'Wagner Dias',route:'Barretos → Bebedouro',volume:20000,capacity:30000,status:'Em rota',eta:'11:55',orders:1},
  {id:'VG-1083',truck:'TRK-09 · FDK-2A18',driver:'Carlos Eduardo',route:'Barretos → Olímpia',volume:27000,capacity:30000,status:'Em rota',eta:'12:42',orders:2},
  {id:'VG-1085',truck:'TRK-10 · DMA-7E55',driver:'Jefferson Reis',route:'Barretos → Terra Roxa',volume:45000,capacity:45000,status:'Em rota',eta:'12:25',orders:3},
  {id:'VG-1086',truck:'TRK-02 · GBC-9F40',driver:'André Luiz',route:'Base Barretos',volume:45000,capacity:45000,status:'Carregando',eta:'Saída 13:20',orders:3},
  {id:'VG-1087',truck:'TRK-07 · EPR-4H16',driver:'Paulo César',route:'Barretos → Colina',volume:20000,capacity:30000,status:'Programada',eta:'Saída 15:00',orders:1},
  {id:'VG-1080',truck:'TRK-11 · GDT-8C54',driver:'Fábio Santos',route:'Guaíra → Barretos',volume:30000,capacity:30000,status:'Concluída',eta:'11:08',orders:2},
];

const initialFleet = [
  {id:'TRK-01',plate:'GAB-1C22',cap:45000,comp:6,driver:'Rogério Lima',status:'base',pos:'Barretos',odo:312400,nextRev:320000,lastRev:'12/08/2026',tireKm:241000,dailyKm:390},
  {id:'TRK-02',plate:'GBC-9F40',cap:45000,comp:6,driver:'André Luiz',status:'carregando',pos:'Barretos',trip:'VG-1086',odo:287900,nextRev:290000,lastRev:'03/07/2026',tireKm:230500,dailyKm:410},
  {id:'TRK-03',plate:'FHT-5A61',cap:30000,comp:5,driver:'Sérgio Nunes',status:'manutencao',pos:'Barretos',note:'Troca de embreagem · previsão 23/09',odo:401200,nextRev:420000,lastRev:'19/09/2026',tireKm:330000,dailyKm:300},
  {id:'TRK-04',plate:'GHF-7D21',cap:45000,comp:6,driver:'Rafael Moreira',status:'rota',pos:'Bebedouro',trip:'VG-1084',busyH:0.7,odo:198300,nextRev:210000,lastRev:'28/08/2026',tireKm:150200,dailyKm:420},
  {id:'TRK-05',plate:'EKL-3B09',cap:30000,comp:5,driver:'Wagner Dias',status:'rota',pos:'Bebedouro',trip:'VG-1082',busyH:0.4,sobra:{product:'Diesel S10',vol:10000},odo:256700,nextRev:270000,lastRev:'15/08/2026',tireKm:199000,dailyKm:360},
  {id:'TRK-06',plate:'GJC-1B93',cap:45000,comp:6,driver:'Leandro Martins',status:'base',pos:'Barretos',odo:144800,nextRev:145600,lastRev:'02/06/2026',tireKm:100000,dailyKm:400},
  {id:'TRK-07',plate:'EPR-4H16',cap:30000,comp:5,driver:'Paulo César',status:'carregando',pos:'Barretos',trip:'VG-1087',odo:338100,nextRev:350000,lastRev:'21/08/2026',tireKm:300000,dailyKm:330},
  {id:'TRK-08',plate:'FRC-6D02',cap:30000,comp:5,driver:'Bruno Ferreira',status:'base',pos:'Barretos',odo:221450,nextRev:230000,lastRev:'10/08/2026',tireKm:140100,dailyKm:350},
  {id:'TRK-09',plate:'FDK-2A18',cap:30000,comp:5,driver:'Carlos Eduardo',status:'rota',pos:'Olímpia',trip:'VG-1083',busyH:1.2,odo:176900,nextRev:190000,lastRev:'01/09/2026',tireKm:120000,dailyKm:380},
  {id:'TRK-10',plate:'DMA-7E55',cap:45000,comp:6,driver:'Jefferson Reis',status:'rota',pos:'Terra Roxa',trip:'VG-1085',busyH:0.9,odo:264300,nextRev:270000,lastRev:'25/07/2026',tireKm:190000,dailyKm:400},
  {id:'TRK-11',plate:'GDT-8C54',cap:30000,comp:5,driver:'Fábio Santos',status:'base',pos:'Barretos',odo:189700,nextRev:200000,lastRev:'05/09/2026',tireKm:150000,dailyKm:340},
  {id:'TRK-12',plate:'GHA-3E77',cap:45000,comp:6,driver:'Marcelo Alves',status:'retorno',pos:'Severínia',odo:305600,nextRev:320000,lastRev:'18/08/2026',tireKm:240000,dailyKm:430},
];
const statusLabel={base:'Na base',retorno:'Retornando vazio',rota:'Em rota',carregando:'Carregando',manutencao:'Manutenção'};
const modeLabel={encaixe:'Encaixe em rota',base:'Sai da garagem',retorno:'Voltando vazio',rota:'Após a entrega atual'};

/* ===== Motor de sugestão do melhor caminhão (considera todas as bases de carregamento) ===== */
function suggest(fleet,sel,bases){
  const ranked=[],excluded=[];
  if(!sel.length) return {ranked,excluded,note:''};
  const garage=(bases.find(b=>b.garage)||bases[0]||{city:'Barretos'}).city;
  const vol=sel.reduce((s,o)=>s+o.volume,0);
  const stops=sel.map(o=>o.city);
  const products=[...new Set(sel.map(o=>o.product))];
  const okBases=bases.filter(b=>products.every(p=>b.products.includes(p)));
  const deadline=Math.min(...sel.map(o=>o.deadlineH));
  const winLabel=sel.find(o=>o.deadlineH===deadline).window;
  if(!okBases.length) return {ranked,excluded,note:`Nenhuma base cadastrada tem ${products.join(' + ')} juntos. Divida em viagens separadas ou cadastre a base em Cadastros.`};
  for(const t of fleet){
    const kmLeft=t.nextRev-t.odo;
    if(t.status==='manutencao'){excluded.push({t,why:`em manutenção (${t.note})`});continue;}
    if(t.status==='carregando'){excluded.push({t,why:`já alocado na ${t.trip}`});continue;}
    const reasons=[];
    let mode,km,arrival,readyH=0,seq,cap=t.cap,base=null;
    const canFit=t.status==='rota'&&t.sobra&&products.length===1&&products[0]===t.sobra.product&&vol<=t.sobra.vol;
    if(canFit){
      mode='encaixe'; cap=t.sobra.vol;
      const r=routeFrom(t.pos,stops); seq=r.seq;
      km=Math.max(0,r.km+dist(r.end,garage)-dist(t.pos,garage));
      arrival=(t.busyH||0)+dist(t.pos,r.seq[0])/VEL_MEDIA;
      reasons.push({tone:'good',text:`Já está em ${t.pos} com ${fmt(t.sobra.vol)} L de ${t.sobra.product} a bordo`});
      reasons.push({tone:'good',text:`Só ${km} km a mais no caminho de volta, sem passar por nenhuma base`});
    } else {
      if(t.cap<vol){excluded.push({t,why:`capacidade de ${fmt(t.cap)} L, menor que a carga de ${fmt(vol)} L`});continue;}
      if(t.comp<sel.length){excluded.push({t,why:`${t.comp} compartimentos para ${sel.length} pedidos`});continue;}
      const busy=t.busyH||0, baseline=dist(t.pos,garage);
      let best=null;
      for(const b of okBases){
        const r=routeFrom(b.city,stops);
        const driven=dist(t.pos,b.city)+r.km+dist(r.end,garage);
        const inc=Math.max(0,driven-baseline);
        const ready=busy+dist(t.pos,b.city)/VEL_MEDIA;
        const arr=ready+b.loadH+dist(b.city,r.seq[0])/VEL_MEDIA;
        const s=inc*CUSTO_KM+Math.max(0,arr-deadline)*600;
        if(!best||s<best.s) best={b,r,driven,inc,ready,arr,s};
      }
      if(kmLeft<best.driven){excluded.push({t,why:`revisão vence no meio da viagem (faltam ${fmt(kmLeft)} km)`});continue;}
      base=best.b; seq=best.r.seq; km=best.inc; readyH=best.ready; arrival=best.arr; mode=t.status;
      const other=base.city!==garage;
      if(mode==='base') reasons.push({tone:'good',text:`Parado na garagem, pronto para sair agora`});
      if(mode==='retorno') reasons.push({tone:other?'good':'warn',text:other?`Voltando vazio de ${t.pos}: passa na ${base.name} no caminho`:`Voltando vazio de ${t.pos}: chega à ${base.name} em ${hrs(readyH)}`});
      if(mode==='rota') reasons.push({tone:other?'good':'warn',text:other?`Termina a entrega em ${t.pos} e carrega na ${base.name}, sem voltar a ${garage}`:`Termina a entrega em ${t.pos} e volta: livre na base às ${clock(readyH)}`});
      reasons.push({tone:'neutral',text:`Carrega na ${base.name} (${base.city}) · ${hrs(base.loadH)} de carregamento`});
    }
    const late=Math.max(0,arrival-deadline);
    if(late>0.05) reasons.push({tone:'bad',text:`Chega ${hrs(late)} depois da janela (${winLabel})`});
    else reasons.push({tone:'good',text:`Chega dentro da janela: ~${clock(arrival)} (limite ${winLabel.replace('Hoje, ','')})`});
    const occ=Math.round(vol/cap*100);
    if(mode!=='encaixe'){
      if(occ>=85) reasons.push({tone:'good',text:`Ocupação de ${occ}%: tanque bem aproveitado`});
      else if(occ<60) reasons.push({tone:'warn',text:`Ocupação de só ${occ}%: sobra capacidade parada`});
      else reasons.push({tone:'neutral',text:`Ocupação de ${occ}%`});
    }
    if(kmLeft<=3000) reasons.push({tone:'warn',text:`Revisão em ${fmt(kmLeft)} km: programar oficina após a viagem`});
    const tirePct=Math.round((t.odo-t.tireKm)/VIDA_PNEU*100);
    if(tirePct>=85) reasons.push({tone:'warn',text:`Pneus com ${tirePct}% da vida útil`});
    const cost=km*CUSTO_KM;
    const score=cost+late*600+(mode==='encaixe'?0:(cap-vol)/1000*6)+(kmLeft<=3000?120:0)+(tirePct>=85?60:0);
    ranked.push({t,mode,km,cost,arrival,readyH,occ,seq,cap,late,score,reasons,base});
  }
  ranked.sort((a,b)=>a.score-b.score);
  return {ranked,excluded,note:''};
}

/* ===== Frota ===== */
function fleetInfo(t){
  const kmLeft=t.nextRev-t.odo;
  const days=Math.max(0,Math.floor(kmLeft/t.dailyKm));
  const tirePct=Math.round((t.odo-t.tireKm)/VIDA_PNEU*100);
  const alerts=[];
  if(t.status==='manutencao') alerts.push({tone:'bad',text:t.note});
  if(kmLeft<=0) alerts.push({tone:'bad',text:'Revisão vencida'});
  else if(kmLeft<=3000) alerts.push({tone:'warn',text:`Revisão em ${fmt(kmLeft)} km (~${days} ${days===1?'dia':'dias'})`});
  if(tirePct>=100) alerts.push({tone:'bad',text:'Pneus acima da vida útil'});
  else if(tirePct>=85) alerts.push({tone:'warn',text:`Pneus com ${tirePct}% da vida útil`});
  return {...t,kmLeft,days,tirePct,alerts,revDate:addDays(days)};
}

/* ===== Rating de clientes ===== */
function rateClients(list,sellers,garage){
  const g=garage||'Barretos';
  const ev=list.map(c=>{ const km=Math.max(dist(g,c.city),8); const custoL=2*km*CUSTO_KM/c.carga; const liq=c.margem-custoL; const s=sellers.find(x=>x.id===c.sellerId); return {...c,seller:s?s.name:'Sem vendedor',km,custoL,liq,result:c.vol*liq}; });
  const maxR=Math.max(1,...ev.map(c=>c.result));
  return ev.map(c=>{
    const parts=[
      {label:'Rentabilidade (resultado R$/mês)',w:50,v:clamp(c.result/maxR*100)},
      {label:'Pagamento em dia',w:25,v:clamp(100-c.atraso*4)},
      {label:'Recorrência de compra',w:15,v:clamp(c.compras/20*100)},
      {label:'Margem líquida por litro',w:10,v:clamp(c.liq/0.13*100)},
    ];
    const score=Math.round(parts.reduce((s,p)=>s+p.v*p.w/100,0));
    const rating=score>=75?'A':score>=60?'B':score>=45?'C':'D';
    return {...c,parts,score,rating};
  });
}
const ratingColor={A:'#1f9d63',B:'#2f7ddd',C:'#e0a030',D:'#d4533f'};
