/* Console interne — Pilotage : Vue d'ensemble, Supervision, Opérations (design dev-admin2.jsx, données réelles). */
const COULEURS_P = ['#E3001B','#E8731A','#1C5FAF','#6D3FD0','#2F8F6E','#0A6A83','#A8620A','#113025'];
const couleurDe = (t) => { let h = 0; for(const ch of String(t||'')) h = (h*31 + ch.charCodeAt(0)) >>> 0; return COULEURS_P[h % COULEURS_P.length]; };
const codeDe = (p) => (p.code || (p.nom||'?').split(/\s+/).filter(Boolean).slice(0,2).map(w=>w[0]).join('')).toUpperCase().slice(0,4);
const PLogo = ({p, s=36}) => <span style={{display:'grid', placeItems:'center', width:s, height:s, borderRadius:s*.3, background:couleurDe(p.nom), color:'#fff', fontWeight:800, fontSize:s*.28, flex:'none', letterSpacing:'-0.02em'}}>{codeDe(p)}</span>;
const Kpi = ({l, v, sub, icon, tone='ok', money}) => <Card pad={18}><div style={{display:'flex', alignItems:'center', gap:10, marginBottom:12}}><Tile icon={icon} s={36} c={TN[tone][1]} bg={TN[tone][0]}/><Lbl style={{flex:1}}>{l}</Lbl></div>{money!=null ? <Money n={money} s={22}/> : <span style={{display:'block', fontFamily:V.disp, fontWeight:800, fontSize:24, letterSpacing:'-0.02em', color:V.ink}}>{v}</span>}{sub && <span style={{display:'block', marginTop:4, fontSize:12, fontWeight:600, color:V.ink3}}>{sub}</span>}</Card>;
const Bar = ({w, c}) => <span style={{display:'block', height:8, borderRadius:99, background:V.sub}}><span style={{display:'block', height:'100%', width:Math.max(0, Math.min(100, w))+'%', borderRadius:99, background:c||V.acc}}></span></span>;
const ASS = (k) => (ASSUREURS[k]||[k])[0];
const pct = (x) => `${String(x ?? 0).replace('.', ',')} %`;
const Erreur = ({e, recharger}) => <Card><EmptyS icon="warning-octagon" tone="bad" title="Chargement impossible" sub={e?.message} action={recharger && <Btn kind="secondary" icon="arrow-clockwise" onClick={recharger}>Réessayer</Btn>}/></Card>;

function A2Home(){
  const {mode} = useAdm(); const [vue, setVue] = React.useState(0);
  const [d, recharger, etat] = useDonnees(() => api('GET', `tableau-de-bord?mode=${mode}`), [mode]);
  const jour = new Date().toLocaleDateString('fr-FR', {weekday:'long', day:'numeric', month:'long', year:'numeric'});
  if(etat.erreur) return <Page max={1280}><PageHead title="Vue d'ensemble"/><Erreur e={etat.erreur} recharger={recharger}/></Page>;
  const k = d?.kpi || {}, f = d?.a_traiter || {}, serie = d?.volume_14j || [], max = Math.max(1, ...serie.map(x=>x.volume));
  const top = d?.top_partenaires || [], maxTop = Math.max(1, ...top.map(x=>x.volume));
  return <Page max={1280}><PageHead title="Vue d'ensemble" sub={`${jour.charAt(0).toUpperCase()+jour.slice(1)} · activité de tous les partenaires`} actions={<><Btn kind="secondary" icon="arrow-clockwise" onClick={recharger}>Actualiser</Btn><Btn icon="plus" onClick={()=>aller('newp')}>Ajouter un partenaire</Btn></>}/>
    {!d ? <Grid cols="repeat(4,1fr)" mcols="1fr 1fr">{[0,1,2,3].map(i=><Card key={i}><Skel h={70}/></Card>)}</Grid> : <>
    <Grid cols="repeat(4,1fr)" mcols="1fr 1fr">
      <Kpi l="Volume débité · mois" money={k.volume_mois} sub="Débits moins remboursements" icon="trend-up"/><Kpi l="Opérations · mois" v={fmt(k.operations_mois)} sub="Contrats émis ce mois" icon="list-checks"/>
      <Kpi l="Partenaires actifs" v={`${k.partenaires_actifs} / ${k.partenaires_total}`} sub={`${k.partenaires_production} en production`} icon="buildings" tone="info"/><Kpi l="Erreurs serveur · 24 h" v={pct(k.taux_erreur_24h)} sub={`${fmt(k.appels_24h)} appels`} icon="warning" tone={k.taux_erreur_24h > 2 ? 'warn' : 'ok'}/></Grid>
    <Grid cols="repeat(3,1fr)">{[['folder-simple-user', `${f.dossiers} dossier${f.dossiers>1?'s':''} à traiter`, f.dossier_plus_ancien ? `Le plus ancien attend depuis ${Depuis(f.dossier_plus_ancien)}` : 'Aucun dossier en attente', 'queue', 'info'],
      ['bank', `${f.depots} dépôt${f.depots>1?'s':''} à rapprocher`, `${fmt(f.depots_declares||0)} F CFA déclarés`, 'deps', 'warn'],
      ['pulse', `${f.a_verifier} opération${f.a_verifier>1?'s':''} à vérifier`, f.a_verifier_plus_ancien ? `Depuis ${Depuis(f.a_verifier_plus_ancien)}` : 'Aucune en attente', 'super', f.a_verifier ? 'bad' : 'ok']].map(x=><Card key={x[3]} onClick={()=>aller(x[3])} style={{display:'flex', alignItems:'center', gap:12}}><Tile icon={x[0]} c={TN[x[4]][1]} bg={TN[x[4]][0]}/><span style={{flex:1}}><span style={{display:'block', fontWeight:800, fontSize:14.5}}>{x[1]}</span><span style={{display:'block', fontSize:12.5, color:V.ink3}}>{x[2]}</span></span><I n="caret-right" s={16} c={V.ink3}/></Card>)}</Grid>
    <Grid cols="minmax(0,1.6fr) minmax(0,1fr)">
      <Card><div style={{display:'flex', alignItems:'center', marginBottom:18}}><H s={16} style={{flex:1}}>Volume débité · 14 jours</H></div>
        <div style={{display:'flex', alignItems:'flex-end', gap:6, height:180}}>{serie.map((x,i)=><span key={x.jour} title={`${new Date(x.jour).toLocaleDateString('fr-FR')} · ${fmt(x.volume)} F CFA`} style={{flex:1, height:Math.max(2, x.volume/max*100)+'%', borderRadius:'6px 6px 2px 2px', background:i===serie.length-1?V.acc:'var(--bar)'}}></span>)}</div>
        <div style={{display:'flex', justifyContent:'space-between', marginTop:6, fontSize:11, color:V.ink3, fontWeight:600}}><span>{serie[0] && new Date(serie[0].jour).toLocaleDateString('fr-FR', {day:'numeric', month:'short'})}</span><span>Aujourd'hui</span></div></Card>
      <Card><H s={16} style={{marginBottom:14}}>Top partenaires · mois</H>{top.length ? top.map(p=><div key={p.partenaire_id} onClick={()=>aller('partner', p.partenaire_id)} className="lr" style={{display:'flex', alignItems:'center', gap:10, marginBottom:14, cursor:'pointer', borderRadius:12}}><PLogo p={p} s={30}/><span style={{flex:1, minWidth:0}}><span style={{display:'flex', marginBottom:5}}><span style={{flex:1, fontWeight:700, fontSize:13, whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis'}}>{p.nom}</span><span style={{fontWeight:800, fontSize:12.5}}>{fmt(p.volume)}</span></span><Bar w={p.volume/maxTop*100}/></span></div>)
        : <Muted>Aucun débit ce mois-ci.</Muted>}</Card>
    </Grid></>}
  </Page>;
}

function AdmSuper(){
  const {mode, rechargerMoi, peut} = useAdm(); const toast = useToast();
  const [d, recharger, etat] = useDonnees(() => api('GET', `supervision?mode=${mode}`), [mode]);
  const [dem, setDem] = React.useState(null), [comm, setComm] = React.useState(''), [occupe, setOccupe] = React.useState(null);
  const agir = async (cle, fn, ok) => { setOccupe(cle); try { const r = await fn(); toast(ok(r)); recharger(); rechargerMoi(); } catch(e){ toast(e.message, 'bad'); } setOccupe(null); };
  if(etat.erreur) return <Page max={1240}><PageHead title="Supervision"/><Erreur e={etat.erreur} recharger={recharger}/></Page>;
  const maxV = Math.max(1, ...(d?.volume_7j||[]).map(x=>x.operations));
  return <Page max={1240}><PageHead title="Supervision" sub="Opérations à vérifier, demandes de résiliation, ajustements à valider, erreurs par assureur." actions={<Btn kind="secondary" icon="arrow-clockwise" onClick={recharger}>Actualiser</Btn>}/>
    <Tbl chargement={!d} head={<div style={{padding:'16px 20px 12px'}}><H s={16}>Opérations à vérifier</H><Muted style={{marginTop:4}}>La réponse de l'assureur s'est perdue : l'argent est retenu. La vérification cherche la preuve chez l'assureur, en lecture seule.</Muted></div>}
      cols={[{k:'r',l:'Référence',w:'1.4fr'},{k:'p',l:'Partenaire',w:'1.4fr'},{k:'i',l:'Assureur',w:'1fr'},{k:'m',l:'Débité',w:'1fr',r:1},{k:'t',l:'Depuis',w:'.8fr'},{k:'x',l:'',w:'170px',r:1}]}
      rows={(d?.a_verifier||[]).map(o=>({r:<span style={{minWidth:0}}><Mono c={V.ink}>{o.reference}</Mono><span style={{display:'block', fontSize:11.5, color:V.ink3}}>{o.immatriculation} · {o.tentatives} vérif.</span></span>, p:o.partenaire, i:ASS(o.assureur), m:<Money n={o.montant_debite} s={13}/>, t:<Badge tone="warn" icon="clock">{Depuis(o.cree_le)}</Badge>,
        x:<Btn sm icon="magnifying-glass" disabled={occupe===o.id} onClick={()=>agir(o.id, ()=>api('POST', `contrats/${o.id}/verifier`), r=>r.statut==='actif'?'Contrat retrouvé : actif':r.statut==='echec'?'Introuvable : échec, débit remboursé':'Toujours à vérifier : nouvel essai plus tard')}>{occupe===o.id?'Vérification…':'Vérifier maintenant'}</Btn>}))}
      empty={<EmptyS icon="check-circle" title="Rien à vérifier" sub="Toutes les opérations ont une réponse de l'assureur."/>}/>
    <Tbl chargement={!d} head={<div style={{padding:'16px 20px 12px'}}><H s={16}>Demandes de résiliation</H><Muted style={{marginTop:4}}>À faire chez l'assureur (Providence l'interdit par API, Askia n'a pas d'endpoint), puis enregistrer ici : le partenaire reçoit contrat.resilie.</Muted></div>}
      cols={[{k:'c',l:'Contrat',w:'1.4fr'},{k:'p',l:'Partenaire',w:'1.2fr'},{k:'i',l:'Assureur',w:'.9fr'},{k:'d',l:'Date d\'effet',w:'.9fr'},{k:'m',l:'Motif',w:'1.2fr'},{k:'x',l:'',w:'120px',r:1}]}
      rows={(d?.demandes||[]).map(x=>({c:<span style={{minWidth:0}}><Mono c={V.ink}>{x.police || x.contrat.slice(0,14)+'…'}</Mono><span style={{display:'block', fontSize:11.5, color:V.ink3}}>{x.immatriculation}</span></span>, p:x.partenaire, i:ASS(x.assureur), d:new Date(x.date_effet).toLocaleDateString('fr-FR'), m:<span style={{color:V.ink2, fontSize:13}}>{x.motif}</span>,
        x:peut('demandes') ? <Btn sm onClick={()=>{setDem(x); setComm('');}}>Traiter</Btn> : null}))}
      empty={<EmptyS icon="check-circle" title="Aucune demande en attente"/>}/>
    {(d?.ajustements||[]).length > 0 && <Tbl head={<div style={{padding:'16px 20px 12px'}}><H s={16}>Ajustements à valider</H><Muted style={{marginTop:4}}>Au-delà du seuil de double validation, un second administrateur doit approuver.</Muted></div>}
      cols={[{k:'p',l:'Partenaire',w:'1.3fr'},{k:'m',l:'Montant',w:'1fr',r:1},{k:'o',l:'Motif',w:'1.5fr'},{k:'u',l:'Demandé par',w:'1fr'},{k:'x',l:'',w:'200px',r:1}]}
      rows={d.ajustements.map(x=>({p:x.partenaire, m:<Money n={x.montant} s={13} sign/>, o:<span style={{color:V.ink2, fontSize:13}}>{x.motif}</span>, u:<span style={{color:V.ink2}}>{x.demande_par}</span>,
        x:x.demande_par_moi ? <Badge tone="mute">Votre demande</Badge> : peut('ajustements') ? <span style={{display:'flex', gap:6}}><Btn kind="secondary" sm disabled={occupe===x.id} onClick={()=>agir(x.id, ()=>api('POST', `ajustements/${x.id}/decision`, {approuver:false}), ()=>'Ajustement refusé')}>Refuser</Btn><Btn sm disabled={occupe===x.id} onClick={()=>agir(x.id, ()=>api('POST', `ajustements/${x.id}/decision`, {approuver:true}), ()=>'Ajustement appliqué')}>Approuver</Btn></span> : null}))}/>}
    <Grid cols="1fr 1fr">
      <Card><H s={16} style={{marginBottom:14}}>Échecs par assureur · 24 h</H>{(d?.assureurs_24h||[]).map(x=><div key={x.assureur} style={{marginBottom:14}}><div style={{display:'flex', marginBottom:6}}><span style={{flex:1, fontWeight:700, fontSize:13.5}}>{ASS(x.assureur)}</span><span style={{fontWeight:800, fontSize:13, color:x.taux>2?V.warn:V.ink}}>{pct(x.taux)}</span><span style={{width:110, textAlign:'right', fontSize:12, color:V.ink3}}>{x.echecs} / {x.operations} opér.</span></div><Bar w={x.taux*20} c={x.taux>2?'var(--warnDot)':V.acc}/></div>)}</Card>
      <Card><H s={16} style={{marginBottom:14}}>Opérations par partenaire · 7 jours</H>{(d?.volume_7j||[]).length ? d.volume_7j.map(p=><div key={p.partenaire_id} style={{display:'flex', alignItems:'center', gap:10, marginBottom:12}}><span style={{width:150, fontSize:13, fontWeight:600, whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis'}}>{p.nom}</span><span style={{flex:1}}><Bar w={p.operations/maxV*100}/></span><span style={{width:50, textAlign:'right', fontSize:12.5, fontWeight:700}}>{p.operations}</span></div>) : <Muted>Aucune opération sur 7 jours.</Muted>}</Card>
    </Grid>
    {dem && <Modal title="Demande de résiliation" icon="file-x" onClose={()=>setDem(null)} foot={<><Btn kind="danger" disabled={comm.length<5 || occupe} onClick={()=>agir(dem.id, ()=>api('POST', `demandes/${dem.id}/decision`, {decision:'refuser', commentaire:comm}), ()=>'Demande refusée').then(()=>setDem(null))}>Refuser</Btn><Btn disabled={occupe} onClick={()=>agir(dem.id, ()=>api('POST', `demandes/${dem.id}/decision`, {decision:'traiter', commentaire:comm}), ()=>'Résiliation enregistrée').then(()=>setDem(null))}>Résiliation faite chez l'assureur</Btn></>}>
      <KV rows={[['Partenaire', dem.partenaire], ['Contrat', dem.police || dem.contrat, null, 1], ['Assureur', ASS(dem.assureur)], ['Véhicule', dem.immatriculation], ['Échéance actuelle', dem.echeance ? new Date(dem.echeance).toLocaleDateString('fr-FR') : '—'], ['Résilier au', new Date(dem.date_effet).toLocaleDateString('fr-FR')], ['Motif', dem.motif]]}/>
      <Notice tone="warn" title="D'abord chez l'assureur">Faites la résiliation dans l'outil de l'assureur, puis enregistrez-la ici. Pas de remboursement (règle commerciale) : un geste passe par un ajustement de solde.</Notice>
      <Field label="Commentaire" hint="Obligatoire pour un refus ; visible par le partenaire." opt><textarea className="li" rows={3} value={comm} onChange={e=>setComm(e.target.value)} style={{...inpCss, height:'auto', padding:12, lineHeight:1.5}}></textarea></Field>
    </Modal>}
  </Page>;
}

const STATUTS_OPS = [['','Tous les statuts'],['actif','Actif'],['a_verifier','À vérifier'],['en_cours','En cours'],['echec','Échec'],['annule','Annulé'],['resilie','Résilié'],['expire','Expiré']];
function A2Ops(){
  const {mode} = useAdm();
  const [q, setQ] = React.useState(() => { try { const v = sessionStorage.getItem('lms_admin_q') || ''; sessionStorage.removeItem('lms_admin_q'); return v; } catch(e){ return ''; } });
  const [qa, setQa] = React.useState(q), [pid, setPid] = React.useState(''), [st, setSt] = React.useState(''), [ins, setIns] = React.useState(''), [page, setPage] = React.useState(1);
  const [parts] = useDonnees(() => api('GET', 'partenaires'), []);
  const [d, recharger, etat] = useDonnees(() => api('GET', `operations?mode=${mode}&page=${page}&q=${encodeURIComponent(qa)}${pid?`&partenaire_id=${pid}`:''}${st?`&statut=${st}`:''}${ins?`&assureur=${ins}`:''}`), [mode, page, qa, pid, st, ins]);
  React.useEffect(() => { const t = setTimeout(() => { setQa(q); setPage(1); }, 350); return () => clearTimeout(t); }, [q]);
  return <Page max={1280}><PageHead title="Opérations" sub="Toutes les opérations de tous les partenaires."/>
    <div style={{display:'flex', gap:8, flexWrap:'wrap'}}><div style={{flex:'1 1 240px'}}><Inp value={q} onChange={e=>setQ(e.target.value)} placeholder="Référence, immatriculation, police, id…" lead={<I n="magnifying-glass" s={17}/>} style={{height:40}}/></div>
      <div style={{width:220}}><Sel label="Partenaire" value={pid} onChange={v=>{setPid(v); setPage(1);}} opts={[['','Tous les partenaires'], ...((parts?.donnees)||[]).map(p=>[String(p.id), p.nom])]} style={{height:40}}/></div>
      <div style={{width:170}}><Sel label="Statut" value={st} onChange={v=>{setSt(v); setPage(1);}} opts={STATUTS_OPS} style={{height:40}}/></div>
      <div style={{width:170}}><Sel label="Assureur" value={ins} onChange={v=>{setIns(v); setPage(1);}} opts={[['','Tous les assureurs'],['askia','Askia'],['providence','La Providence']]} style={{height:40}}/></div></div>
    {etat.erreur ? <Erreur e={etat.erreur} recharger={recharger}/> :
    <Tbl chargement={!d} cols={[{k:'r',l:'Référence',w:'1.3fr'},{k:'p',l:'Partenaire',w:'1fr'},{k:'a',l:'Assuré',w:'1fr',hideM:1},{k:'i',l:'Assureur',w:'.8fr'},{k:'px',l:'Prix client',w:'.9fr',r:1},{k:'d',l:'Débité',w:'.9fr',r:1},{k:'c',l:'Date',w:'.8fr',hideM:1},{k:'s',l:'Statut',w:'1fr'}]}
      rows={(d?.donnees||[]).map(o=>({r:<span style={{minWidth:0}}><Mono c={V.ink}>{o.reference}</Mono><span style={{display:'block', fontSize:11.5, color:V.ink3}}>{o.immatriculation}{o.police ? ` · ${o.police}` : ''}</span></span>, p:<span onClick={e=>{e.stopPropagation(); aller('partner', o.partenaire_id);}} style={{display:'flex', alignItems:'center', gap:6, cursor:'pointer', minWidth:0}}><PLogo p={{nom:o.partenaire, code:o.partenaire_code}} s={22}/><span style={{overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}}>{o.partenaire}</span></span>,
        a:o.assure, i:ASS(o.assureur), px:<Money n={o.prix_client} s={13} muted/>, d:<Money n={o.montant_debite} s={13}/>, c:<span style={{color:V.ink2, fontSize:12.5}}>{DC(o.cree_le)}</span>, s:<StatusB st={o.statut}/>}))}
      empty={<EmptyS icon="list-checks" title="Aucune opération" sub="Aucune opération ne correspond à ces filtres."/>} foot={d && d.total > 25 && <Pager n={d.total} page={page} set={setPage}/>}/>}
  </Page>;
}
Object.assign(window, {PLogo, Kpi, Bar, ASS, pct, Erreur, A2Home, AdmSuper, A2Ops, couleurDe, codeDe});
