const __clubMap=new Map(FOOTBALL_DATA.clubs.map(c=>[c.id,c]));
const __playerMap=new Map(FOOTBALL_DATA.players.map(p=>[p.id,p]));
let __squadMap=new Map();
function __reindexSquads(){__squadMap=new Map();for(const p of FOOTBALL_DATA.players){if(!__squadMap.has(p.clubId))__squadMap.set(p.clubId,[]);__squadMap.get(p.clubId).push(p)}}
__reindexSquads();
const Engine={
 clamp:(n,a,b)=>Math.max(a,Math.min(b,n)),
 rand:a=>a[Math.floor(Math.random()*a.length)],
 club:id=>__clubMap.get(id),
 player:id=>__playerMap.get(id),
 squad:id=>(__squadMap.get(id)||[]),
 reindexPlayers:()=>__reindexSquads(),
 profile:id=>FOOTBALL_DATA.profiles.find(p=>p.id===id),
 posFr(code){
  const m={GK:"Gardien",RB:"Arrière droit",LB:"Arrière gauche",CB:"Défenseur central",DM:"Milieu défensif",CM:"Milieu central",AM:"Milieu offensif",RW:"Ailier droit",LW:"Ailier gauche",ST:"Avant-centre"};
  return m[code]||code;
 },
 positionScore(p,pos){
  if(p.pos===pos)return 18;
  const groups={GK:["GK"],RB:["RB","CB"],LB:["LB","CB"],CB:["CB","RB","LB"],DM:["DM","CM"],CM:["CM","DM","AM"],AM:["AM","CM","RW","LW"],RW:["RW","AM","ST"],LW:["LW","AM","ST"],ST:["ST","RW","LW"]};
  return (groups[pos]||[]).includes(p.pos)?8:-6;
 },
 autoXI(id,formation){
  const need=FOOTBALL_DATA.formations[formation]||FOOTBALL_DATA.formations["4-3-3"],pool=this.squad(id).filter(p=>!p.injury&&!p.suspension),used=new Set(),xi=[];
  need.forEach(pos=>{
    const p=pool.filter(x=>!used.has(x.id)).sort((a,b)=>
      (b.rating+this.positionScore(b,pos)+b.fitness/50+b.sharpness/100)-
      (a.rating+this.positionScore(a,pos)+a.fitness/50+a.sharpness/100))[0];
    if(p){used.add(p.id);xi.push(p.id)}
  });
  return xi;
 },
 clubPower(id,xi,tactic){
  const ps=(xi||this.autoXI(id,"4-3-3")).map(x=>this.player(x)).filter(Boolean);
  let r=ps.reduce((s,p)=>s+p.rating*(0.82+p.fitness/520)+p.sharpness/40,0)/(ps.length||1);
  if(tactic==="Attaque")r+=1.0;
  if(tactic==="Pressing")r+=0.6;
  if(tactic==="Défense")r+=0.3;
  return r;
 },
 expectedGoals(powerA,powerB,homeBonus=0){
  const diff=(powerA+homeBonus-powerB);
  return this.clamp(1.25+diff/12,0.25,3.2);
 },
 poisson(lambda){
  let L=Math.exp(-lambda),k=0,p=1;
  do{k++;p*=Math.random()}while(p>L&&k<10);
  return k-1;
 },
 realisticScore(powerA,powerB,homeBonus=1.2){
  let hg=this.poisson(this.expectedGoals(powerA,powerB,homeBonus));
  let ag=this.poisson(this.expectedGoals(powerB,powerA,0));
  // Strong teams usually prevail unless random event swings it.
  const diff=powerA-powerB;
  if(Math.abs(diff)>=7 && Math.random()<0.68){
    if(diff>0 && hg<=ag) hg=ag+1+Math.floor(Math.random()*2);
    if(diff<0 && ag<=hg) ag=hg+1+Math.floor(Math.random()*2);
  }
  // upset chance
  if(Math.abs(diff)>=8 && Math.random()<0.12){
    if(diff>0){ag=Math.max(ag,hg+1)}
    else{hg=Math.max(hg,ag+1)}
  }
  return [hg,ag];
 },
 weightedScorer(xi){
  const ps=xi.map(id=>this.player(id)).filter(Boolean),w=[];
  ps.forEach(p=>{
    let n=["ST"].includes(p.pos)?8:["RW","LW","AM"].includes(p.pos)?5:["CM","DM"].includes(p.pos)?2:1;
    for(let i=0;i<n;i++)w.push(p);
  });
  return this.rand(w.length?w:ps);
 },
 weightedCreator(xi,exclude){
  const ps=xi.map(id=>this.player(id)).filter(p=>p&&p.id!==exclude),w=[];
  ps.forEach(p=>{
    let n=["AM","RW","LW","CM"].includes(p.pos)?5:["DM","ST"].includes(p.pos)?2:1;
    for(let i=0;i<n;i++)w.push(p);
  });
  return this.rand(w.length?w:ps);
 },
 formatMoney(n){if(n>=1e9)return (n/1e9).toFixed(1)+" Md€";if(n>=1e6)return (n/1e6).toFixed(1)+" M€";if(n>=1e3)return Math.round(n/1e3)+" k€";return n+" €"},
 schedule(ids){
  let a=[...ids];if(a.length%2)a.push(null);let rounds=[],arr=a.slice();
  for(let r=0;r<a.length-1;r++){
    let g=[];
    for(let i=0;i<a.length/2;i++){let x=arr[i],y=arr[a.length-1-i];if(x&&y)g.push(r%2?[y,x]:[x,y])}
    rounds.push(g);
    arr=[arr[0],arr[arr.length-1],...arr.slice(1,-1)];
  }
  return [...rounds,...rounds.map(g=>g.map(([x,y])=>[y,x]))]
 }
};