/* Football Manager Retro 4.0 – Player DNA & attribute-based match engine */
(function(){
  'use strict';
  const posGroup=p=>p==='TW'?'TW':['IV','RV','LV','LIB'].includes(p)?'ABW':['DM','ZM','OM','RA','LA','RM','LM'].includes(p)?'MIT':'ST';
  const R=(a,b)=>typeof rand==='function'?rand(a,b):Math.floor(Math.random()*(b-a+1))+a;
  const C=(v,a=1,b=100)=>typeof clamp==='function'?clamp(v,a,b):Math.max(a,Math.min(b,v));
  const orientationFor=pos=>posGroup(pos)==='ST'?'Offensiv':posGroup(pos)==='ABW'||pos==='TW'?'Defensiv':'Ausgeglichen';
  function dnaValue(base,spread=12){return C(Math.round(base+R(-spread,spread)));}
  function createDNA(p){
    const base=Number(p.rating)||65, group=posGroup(p.position), age=Number(p.age)||25;
    const heightBase=group==='TW'?190:group==='ABW'?186:group==='ST'?183:178;
    const speedMod=group==='ST'?5:group==='MIT'?3:group==='ABW'?-1:-8;
    const headMod=group==='ABW'||group==='ST'?7:group==='TW'?-5:-2;
    const shotMod=group==='ST'?8:group==='MIT'?3:group==='ABW'?-7:-15;
    return {
      height:C(Math.round(heightBase+R(-9,9)),165,205),
      orientation:orientationFor(p.position),
      form:C(p.form??R(55,82)),
      speed:dnaValue(base+speedMod-(age>31?4:0)),
      heading:dnaValue(base+headMod),
      shotPower:dnaValue(base+shotMod),
      stamina:dnaValue(base+(age<24?3:age>31?-5:0)),
      hidden:{
        injuryProneness:C(R(8,72)), motivation:C(R(42,94)), skill:dnaValue(base,15),
        consistency:C(R(40,92)), discipline:C(R(38,95)), learning:C(R(35,96))
      }
    };
  }
  function ensurePlayerDNA(p){
    if(!p)return p;
    const generated=createDNA(p);p.dna=p.dna||{};
    ['height','orientation','form','speed','heading','shotPower','stamina'].forEach(k=>{if(p.dna[k]===undefined)p.dna[k]=generated[k];});
    p.dna.hidden=p.dna.hidden||{};Object.keys(generated.hidden).forEach(k=>{if(p.dna.hidden[k]===undefined)p.dna.hidden[k]=generated.hidden[k];});
    p.form=p.dna.form;
    return p;
  }
  function allClubs(){
    const out=[];
    if(state?.league?.clubs)out.push(...state.league.clubs);
    (state?.v22?.worldLeagues||[]).forEach(l=>out.push(...(l.clubs||[])));
    return [...new Map(out.filter(Boolean).map(c=>[c.id||c.name,c])).values()];
  }
  function ensureAllPlayerDNA(){
    if(!state)return;allClubs().forEach(c=>(c.squad||[]).forEach(ensurePlayerDNA));
    state.playerDna ||= {version:40,lastTraining:[],lastCamp:[],lastMatchDevelopment:[],injuryLog:[]};
  }
  globalThis.ensurePlayerDNA=ensurePlayerDNA;globalThis.ensureAllPlayerDNA=ensureAllPlayerDNA;

  if(typeof makePlayer==='function'){
    const oldMakePlayer=makePlayer;
    makePlayer=function(...args){return ensurePlayerDNA(oldMakePlayer(...args));};
  }

  function playerEffective(p){
    ensurePlayerDNA(p);const d=p.dna,h=d.hidden,group=posGroup(p.position);
    const base={TW:p.rating*.45+d.form*.14+d.stamina*.06+h.skill*.18+h.motivation*.07+p.fitness*.10+h.consistency*.06,
      ABW:p.rating*.31+d.form*.12+d.speed*.10+d.heading*.13+d.stamina*.10+h.skill*.07+h.motivation*.05+p.fitness*.12,
      MIT:p.rating*.29+d.form*.13+d.speed*.08+d.shotPower*.07+d.stamina*.14+h.skill*.12+h.motivation*.05+p.fitness*.12,
      ST:p.rating*.28+d.form*.14+d.speed*.13+d.heading*.12+d.shotPower*.15+d.stamina*.06+h.skill*.05+h.motivation*.03+p.fitness*.04}[group];
    const orientBonus=(group==='ST'&&d.orientation==='Offensiv')||(group==='ABW'&&d.orientation==='Defensiv')?1.5:0;
    return base+orientBonus;
  }
  globalThis.playerEffectivePower=playerEffective;
  if(typeof teamPower==='function'){
    teamPower=function(club){
      ensureAllPlayerDNA();let players=(club.id===state?.userClubId?(state.selectedXI||[]).map(id=>club.squad.find(p=>p.id===id)).filter(Boolean):[...(club.squad||[])].filter(p=>(p.injuryGames||0)<=0&&(p.suspensionGames||0)<=0).sort((a,b)=>playerEffective(b)-playerEffective(a)).slice(0,11));
      if(players.length<11)players=[...(club.squad||[])].sort((a,b)=>playerEffective(b)-playerEffective(a)).slice(0,11);
      const avg=players.reduce((s,p)=>s+playerEffective(p),0)/Math.max(1,players.length);
      return avg+(club.rating||70)*.08;
    };
  }

  function weightedPlayer(club,kind){
    const pool=(club.squad||[]).filter(p=>(p.injuryGames||0)<=0&&(p.suspensionGames||0)<=0&&(kind!=='attack'||posGroup(p.position)!=='TW'));
    if(!pool.length)return null;const weights=pool.map(p=>{ensurePlayerDNA(p);const d=p.dna,h=d.hidden;
      if(kind==='header')return Math.max(1,d.heading+(d.height-175)*1.2+d.form*.3);
      if(kind==='shot')return Math.max(1,d.shotPower+d.speed*.25+d.form*.35+h.skill*.2);
      if(kind==='card')return Math.max(1,115-h.discipline+(d.orientation==='Defensiv'?8:0));
      return Math.max(1,p.rating+d.speed*.25+d.form*.25+h.motivation*.15);
    });let x=Math.random()*weights.reduce((a,b)=>a+b,0);for(let i=0;i<pool.length;i++){x-=weights[i];if(x<=0)return pool[i];}return pool.at(-1);
  }
  function eventText(type,club,p){
    const name=p?.name||'ein Spieler';
    const texts={chance:`${club.name}: ${name} kommt gefährlich zum Abschluss.`,header:`${name} steigt nach einer Flanke hoch und köpft auf das Tor.`,goal:`TOR für ${club.name}! ${name} trifft.`,save:`Der Torwart pariert den Versuch von ${name}.`,card:`Gelbe Karte für ${name} (${club.name}).`,injury:`${name} muss verletzt vom Feld.`,corner:`Ecke für ${club.name}.`};
    return texts[type]||`${club.name} baut einen Angriff auf.`;
  }
  if(typeof processLiveMinute==='function'){
    processLiveMinute=function(){
      if(!liveMatch)return;ensureAllPlayerDNA();const m=liveMatch.minute;if(m===45){addLiveEvent(m,'halftime',commentary('halftime'));return;}
      const total=Math.max(1,liveMatch.homePower+liveMatch.awayPower),homeAttack=Math.random()<liveMatch.homePower/total;
      const club=homeAttack?liveMatch.home:liveMatch.away,opp=homeAttack?liveMatch.away:liveMatch.home;
      const userClub=club.id===state.userClubId,tactic=userClub?(liveMatch.tactic||'balanced'):'balanced',aggression=userClub?(liveMatch.aggression||'fair'):'fair';
      const tacticChance=tactic==='offensive'?.012:tactic==='defensive'?-0.005:0;
      const chanceRate=.046+tacticChance,cardRate=aggression==='hard'?.012:.0045;
      const roll=Math.random();
      if(roll<chanceRate){
        const header=Math.random()<.30,p=weightedPlayer(club,header?'header':'shot');if(!p)return;const d=p.dna,h=d.hidden;
        addLiveEvent(m,header?'header':'chance',eventText(header?'header':'chance',club,p),club.id,p.id);
        const attack=(header?(d.heading+(d.height-170)*.9):(d.shotPower*.65+d.speed*.18+h.skill*.25))+d.form*.25+p.rating*.45;
        const defending=teamPower(opp)*1.4+R(-18,18);const finish=C(.15+(attack-defending)/170,.07,.62);
        if(Math.random()<finish){if(homeAttack)liveMatch.homeGoals++;else liveMatch.awayGoals++;p.goals=(p.goals||0)+1;d.form=C(d.form+R(2,5));addLiveEvent(m,'goal',eventText('goal',club,p),club.id,p.id);}else addLiveEvent(m,'save',eventText('save',club,p),club.id,p.id);
      }else if(roll<chanceRate+.018){const p=weightedPlayer(club,'attack');addLiveEvent(m,'corner',eventText('corner',club,p),club.id,p?.id);}
      else if(roll<chanceRate+.018+cardRate){const p=weightedPlayer(club,'card');if(p){p.yellowCards=(p.yellowCards||0)+1;addLiveEvent(m,'yellow',eventText('card',club,p),club.id,p.id);}}
      // bewusst seltene Kurzzeitverletzungen; Risiko basiert auf versteckter Anfälligkeit, Fitness und Kondition
      if(Math.random()<.00022){const p=weightedPlayer(club,'attack');if(p&&!(p.injuryGames>0)){const risk=(p.dna.hidden.injuryProneness+(100-p.fitness)+(100-p.dna.stamina))/300;if(Math.random()<risk){p.injuryGames=R(1,p.dna.hidden.injuryProneness>75?3:2);p.injuryName=['Prellung','leichte Zerrung','Überlastung'][R(0,2)];state.playerDna.injuryLog.unshift({week:state.week,name:p.name,injury:p.injuryName,games:p.injuryGames});addLiveEvent(m,'injury',eventText('injury',club,p),club.id,p.id);}}
    };
  }

  function attributeSnapshot(p){ensurePlayerDNA(p);return {rating:p.rating,form:p.dna.form,speed:p.dna.speed,heading:p.dna.heading,shotPower:p.dna.shotPower,stamina:p.dna.stamina};}
  function diffSnapshots(before,players){return players.flatMap(p=>{const b=before.get(p.id);if(!b)return[];const changes=[];for(const [k,label] of Object.entries({rating:'Stärke',form:'Form',speed:'Schnelligkeit',heading:'Kopfball',shotPower:'Schusskraft',stamina:'Kondition'})){const now=k==='rating'?p.rating:p.dna[k];if(now>b[k])changes.push(`${label} ${b[k]}→${now}`);}return changes.length?[{id:p.id,name:p.name,changes}]:[];});}
  function trainAttributes(camp=false){
    const c=getUserClub(),focus=state.training?.focus||'general';const map={attack:['shotPower','speed'],midfield:['stamina','speed'],defence:['heading','stamina'],goalkeeper:['form','stamina'],general:['form','stamina']};
    (c.squad||[]).forEach(p=>{ensurePlayerDNA(p);const h=p.dna.hidden,keys=map[focus]||map.general;const chance=(camp?.24:.035)+(h.motivation+h.learning-100)/900;
      keys.forEach(k=>{if(Math.random()<chance)p.dna[k]=C(p.dna[k]+1);});
      if(Math.random()<(camp?.12:.018)+(h.learning-50)/1500&&p.rating<p.potential)p.rating++;
      // Anfällige Spieler werden bei hoher Intensität etwas wahrscheinlicher, Verletzungen bleiben selten und kurz.
      const intensity=state.training?.intensity||'normal',injuryChance=(intensity==='high'?.0016:intensity==='light'?.00025:.00065)*(h.injuryProneness/50)*(105-p.fitness)/35;
      if(!camp&&!(p.injuryGames>0)&&Math.random()<injuryChance){p.injuryGames=R(1,h.injuryProneness>78?3:2);p.injuryName=['Zerrung','Prellung','Überlastung'][R(0,2)];}
    });
  }
  if(typeof runWeeklyTraining==='function'){
    const old=runWeeklyTraining;runWeeklyTraining=function(){ensureAllPlayerDNA();const players=getUserClub().squad,before=new Map(players.map(p=>[p.id,attributeSnapshot(p)]));old();trainAttributes(false);state.playerDna.lastTraining=diffSnapshots(before,players);if(state.playerDna.lastTraining.length)state.news.unshift(`Player-DNA Training: ${state.playerDna.lastTraining.map(x=>`${x.name}: ${x.changes.join(', ')}`).join(' · ')}`);};
  }
  if(typeof startTrainingCamp==='function'){
    const old=startTrainingCamp;startTrainingCamp=function(){ensureAllPlayerDNA();const players=getUserClub().squad,before=new Map(players.map(p=>[p.id,attributeSnapshot(p)]));const oldCooldown=state.training?.campCooldown||0,oldBalance=getUserClub().balance;old();if((state.training?.campCooldown||0)>oldCooldown||getUserClub().balance<oldBalance){trainAttributes(true);state.playerDna.lastCamp=diffSnapshots(before,players);save();render();}};
  }

  const visibleLabels={height:'Größe',orientation:'Ausrichtung',form:'Form',speed:'Tempo',heading:'Kopfball',shotPower:'Schusskraft',stamina:'Kondition'};
  function attrChip(k,v){return `<span class="attribute-chip"><small>${visibleLabels[k]}</small> <b>${k==='height'?`${v} cm`:v}</b></span>`;}
  function developmentHtml(items,title){return `<div class="card"><h3>${title}</h3>${items?.length?items.map(x=>`<div class="news"><b>${esc(x.name)}</b>: ${x.changes.map(esc).join(', ')}</div>`).join(''):'<p class="muted">Keine messbare Verbesserung.</p>'}</div>`;}
  if(typeof squad==='function'){
    squad=function(){ensureAllPlayerDNA();const c=getUserClub();const players=[...c.squad].sort((a,b)=>{const order={TW:0,RV:1,IV:2,LV:3,DM:4,ZM:5,OM:6,RA:7,LA:8,ST:9};return (order[a.position]??10)-(order[b.position]??10)||b.rating-a.rating;});
      return `<div class="card"><h2>Kader – ${esc(c.name)}</h2><p class="muted">Die sichtbaren Player-DNA-Werte beeinflussen Training, Form, Verletzungen und jede Spielsituation. Versteckte Werte werden nicht angezeigt.</p><div class="table-scroll"><table class="dna-table"><thead><tr><th>Pos</th><th>Spieler</th><th>Alter</th><th>Größe</th><th>Ausrichtung</th><th>Stärke</th><th>Fitness</th><th>Form</th><th>Tempo</th><th>Kopfball</th><th>Schusskraft</th><th>Kondition</th><th>Status</th><th>Wert</th></tr></thead><tbody>${players.map(p=>{ensurePlayerDNA(p);const d=p.dna;return `<tr><td><span class="badge">${p.position}</span></td><td><b>${esc(p.name)}</b></td><td>${p.age}</td><td>${d.height} cm</td><td>${d.orientation}</td><td><b>${p.rating}</b></td><td>${p.fitness}%</td><td>${d.form}</td><td>${d.speed}</td><td>${d.heading}</td><td>${d.shotPower}</td><td>${d.stamina}</td><td>${p.injuryGames?`<span class="injured">${esc(p.injuryName)} (${p.injuryGames})</span>`:p.suspensionGames?`Gesperrt (${p.suspensionGames})`:'Fit'}</td><td>${money(p.value)}</td></tr>`}).join('')}</tbody></table></div></div>`;
    };
  }
  if(typeof lineup==='function'){
    const oldLineup=lineup;lineup=function(){ensureAllPlayerDNA();const html=oldLineup();return html.replace(/\((TW|RV|IV|LV|DM|ZM|OM|RA|LA|ST),\s*(\d+)\)/g,(m,pos,rating)=>m);};
  }
  if(typeof training==='function'){
    const old=training;training=function(){ensureAllPlayerDNA();return old()+`<div class="grid cols-2" style="margin-top:16px">${developmentHtml(state.playerDna.lastTraining,'Player-DNA: letztes Training')}${developmentHtml(state.playerDna.lastCamp,'Player-DNA: letztes Trainingslager')}</div>`;};
  }
  if(typeof render==='function'){
    const old=render;render=function(){ensureAllPlayerDNA();old();const label=document.querySelector('#seasonLabel');if(label&&state)label.textContent=label.textContent.replace(/Version\s+[\d.]+/,'Version 4.0 · Player DNA');};
  }
  if(typeof load==='function'){
    const old=load;load=function(){old();if(state){ensureAllPlayerDNA();save();render();}};
  }
  if(typeof newGame==='function'){
    const old=newGame;newGame=function(...args){old(...args);ensureAllPlayerDNA();save();render();};
  }
  document.addEventListener('DOMContentLoaded',()=>{globalThis.FMDataStore?.load?.();});
}
})();
