// fp-data.jsx v4 — 9 Agents + WEATHER, i18n, Odds Comparison, H2H, Auto-date

// ─── i18n ─────────────────────────────────────────────────────
const TRANSLATIONS = {
  de: {
    today:'Heutige Spiele', matches:'Spiele', topEvents:'TOP EVENTS',
    moreMatches:'WEITERE SPIELE', analyse:'KI Analyse', addTicket:'+ Schein',
    agents:'Agenten', tickets:'Scheine', daily:'Daily', bankroll:'Bankroll', info:'Info',
    startAgents:'18 KI-MODELLE STARTEN', reanalyse:'Neu analysieren',
    running:'Welle', of:'/', wave1:'WELLE 1 · FAKTEN', wave2:'WELLE 2 · KONTEXT',
    wave3:'WELLE 3 · RISIKO', wave4:'WELLE 4 · ENTSCHEIDUNG',
    masterDecision:'MASTER ENTSCHEIDUNG', odds:'QUOTE', confidence:'KONFIDENZ',
    safe:'SICHER', good:'AUSGEWOGEN', risk:'RISIKO',
    kiTickets:'KI-SCHEINE', myTicket:'MEIN SCHEIN', stats:'STATS',
    share:'Teilen', track:'Tracken', performance:'Performance',
    bankrollMgr:'Bankroll Manager', disclaimer:'⚠️ Nur zu Informationszwecken. Spiele verantwortungsvoll. 18+',
    noMatches:'Keine Spiele für diese Liga', allLeagues:'Alle',
    homeWin:'Heimsieg', draw:'Unentschieden', awayWin:'Auswärtssieg',
    h2hHistory:'H2H Verlauf', loading:'Lädt...', error:'Fehler',
    liveOdds:'LIVE QUOTEN', comparison:'Quoten-Vergleich',
    weather:'WETTER', analysing:'Analysiert...',
    kelly:'Kelly', bankrollGoal:'Ziel', stake:'Einsatz',
    waiting:'wartet', generateFailed:'KI-Generierung fehlgeschlagen. Bitte erneut versuchen.',
    retry:'Erneut versuchen', generating:'KI generiert Scheine...',
    headerSub:'9 AGENTEN · WETTER · KELLY',
    noTicket:'Noch keine Auswahl', addFromToday:'"Heute" → Analysieren → "+Schein"',
    useSlip:'Schein übernehmen', newSlips:'Neue Scheine',
    error_conn:'Verbindungsfehler.', waitingSuffix:'— wartet...',
    pendingWave:'Welle', analyzing:'Analysiert',tabToday:'Heute',tabAgents:'Agenten',tabTickets:'Scheine',tabTicker:'Ticker',tabBankroll:'Bankroll',tabInfo:'Info',
    // Schein-Tab
    classic:'Klassisch', halftime:'Halbzeit', corners:'Korner', edge:'Edge', mine:'Mein',
    classicDesc:'Safe · Balanced · Risk', halftimeDesc:'HZ-Märkte · Safe · Balanced · Risk', cornersDesc:'Korner-Märkte · Safe · Balanced · Risk',
    saved:'Gespeichert', generateNew:'Neu generieren', generating2:'Generiere…',
    edgeHunter:'Edge-Hunter', edgeHunterSub:'QUANT EDGE-HUNTER · 10k SIMS/SPIEL',
    valuePicks:'VALUE-PICKS', avgEdge:'Ø Edge', topToSlip:'Top 6 → Schein',
    noEdgesFound:'Keine Edges ≥ {x}% bei den aktuellen Quoten.', loweringThreshold:'Schwellwert senken oder neu rechnen.',
    manualSlip:'MANUELLER SCHEIN', combo:'KOMBI', system:'SYSTEM', sysFehler:'K/N · FEHLER ERLAUBT', sysVollett:'VOLLETT · ALLE KOMBINATIONEN',
    needsPicks:'Benötigt {n} Picks (du hast {m})',
    overGoals:'Über 2.5 Tore', underGoals:'Unter 2.5 Tore', bttsYes:'Beide treffen — Ja', bttsNo:'Beide treffen — Nein',
    // Agenten-Tab
    waveRunning:'Welle {w}/4 läuft', agentsAnalysing:'18 KI-Modelle analysieren das Spiel — Ergebnis kommt gleich.',
    tapToStart:'Tippe "18 KI-Modelle starten" für die Master-Entscheidung.',
    strongConsensus:'Starker Konsens — {n}/9 Agenten einheitlich',
    home_:'Heim', away_:'Gast', fresh:'frisch', tired:'müde', normalRest:'normal',
    lineupConfirmed:'Aufstellung bestätigt', lineupPending:'Aufstellung pending',
    // Motivation-Kategorien
    cat_title_race:'Titel-Kampf', cat_relegation_fight:'Abstiegszone', cat_relegation_threat:'Abstiegsgefährdet',
    cat_european_chase:'Europa-Plätze', cat_champion_secure:'Titel sicher', cat_dead_rubber:'Tot-Spiel',
    cat_midtable:'Mid-Table', cat_derby:'Derby',
    // Quant
    quantBlend:'QUANT-BLEND', poissonQuant:'POISSON QUANT · 10k SIMS', valuePick:'★ VALUE PICK',
    // Groq
    groqAgrees:'STIMMT ZU', groqDissent:'EIGENE MEINUNG',
    // Track-Record
    trackRecord:'📊 TRACK-RECORD', picks_:'PICKS', hitRate:'HIT-RATE', roi_:'ROI', brier:'BRIER',
    evaluated:'ausgewertet', open_:'offen', perPick:'Pro Pick (1u Stake)', lowerBetter:'Niedriger = besser',
    bySource:'PRO QUELLE', clvLabel:'★ CLOSING LINE VALUE',
    clvWin:'✓ Du schlägst die Closing-Line — langfristig +EV.',
    clvLose:'Closing-Line schlägt dich. System braucht Re-Kalibrierung.',
    exportJson:'📥 Export JSON', resetBtn:'🗑️ Reset',
    confirmReset:'Alle Picks und Statistiken wirklich löschen?',
    // Misc
    noAlt:'Keine sinnvolle Alternative', connectionFailed:'KI-Verbindung unterbrochen.',
  },
  en: {
    today:"Today's Matches", matches:'Matches', topEvents:'TOP EVENTS',
    moreMatches:'MORE MATCHES', analyse:'AI Analyse', addTicket:'+ Slip',
    agents:'Agents', tickets:'Tickets', daily:'Daily', bankroll:'Bankroll', info:'Info',
    startAgents:'START 18 AI MODELS', reanalyse:'Re-analyse',
    running:'Wave', of:'/', wave1:'WAVE 1 · FACTS', wave2:'WAVE 2 · CONTEXT',
    wave3:'WAVE 3 · RISK', wave4:'WAVE 4 · DECISION',
    masterDecision:'MASTER DECISION', odds:'ODDS', confidence:'CONFIDENCE',
    safe:'SAFE', good:'BALANCED', risk:'RISK',
    kiTickets:'AI SLIPS', myTicket:'MY SLIP', stats:'STATS',
    share:'Share', track:'Track', performance:'Performance',
    bankrollMgr:'Bankroll Manager', disclaimer:'⚠️ For info only. Gamble responsibly. 18+',
    noMatches:'No matches for this league', allLeagues:'All',
    homeWin:'Home Win', draw:'Draw', awayWin:'Away Win',
    h2hHistory:'H2H History', loading:'Loading...', error:'Error',
    liveOdds:'LIVE ODDS', comparison:'Odds Comparison',
    weather:'WEATHER', analysing:'Analysing...',
    kelly:'Kelly', bankrollGoal:'Goal', stake:'Stake',
    waiting:'waiting', generateFailed:'AI generation failed. Please try again.',
    retry:'Try Again', generating:'AI generating slips...',
    headerSub:'9 AGENTS · WEATHER · KELLY',
    noTicket:'No selections yet', addFromToday:'"Today" → Analyse → "+Slip"',
    useSlip:'Use Slip', newSlips:'New Slips',
    error_conn:'Connection error.', waitingSuffix:'— waiting...',
    pendingWave:'Wave', analyzing:'Analysing',tabToday:'Today',tabAgents:'Agents',tabTickets:'Tickets',tabTicker:'Ticker',tabBankroll:'Bankroll',tabInfo:'Info',
    classic:'Classic', halftime:'Half Time', corners:'Corners', edge:'Edge', mine:'Mine',
    classicDesc:'Safe · Balanced · Risk', halftimeDesc:'HT markets · Safe · Balanced · Risk', cornersDesc:'Corner markets · Safe · Balanced · Risk',
    saved:'Saved', generateNew:'Generate New', generating2:'Generating…',
    edgeHunter:'Edge Hunter', edgeHunterSub:'QUANT EDGE HUNTER · 10k SIMS/MATCH',
    valuePicks:'VALUE PICKS', avgEdge:'Ø Edge', topToSlip:'Top 6 → Slip',
    noEdgesFound:'No edges ≥ {x}% at current odds.', loweringThreshold:'Lower threshold or refresh.',
    manualSlip:'MANUAL SLIP', combo:'ACCA', system:'SYSTEM', sysFehler:'K/N · ERRORS ALLOWED', sysVollett:'FULL COVER · ALL COMBINATIONS',
    needsPicks:'Needs {n} picks (you have {m})',
    overGoals:'Over 2.5 Goals', underGoals:'Under 2.5 Goals', bttsYes:'Both Teams Score — Yes', bttsNo:'Both Teams Score — No',
    waveRunning:'Wave {w}/4 running', agentsAnalysing:'18 AI models analysing — result coming up.',
    tapToStart:'Tap "Start 18 AI Models" for the master decision.',
    strongConsensus:'Strong consensus — {n}/9 agents unanimous',
    home_:'Home', away_:'Away', fresh:'fresh', tired:'tired', normalRest:'normal',
    lineupConfirmed:'Lineup confirmed', lineupPending:'Lineup pending',
    cat_title_race:'Title Race', cat_relegation_fight:'Relegation Zone', cat_relegation_threat:'Relegation Risk',
    cat_european_chase:'European Spots', cat_champion_secure:'Title Secure', cat_dead_rubber:'Dead Rubber',
    cat_midtable:'Mid-Table', cat_derby:'Derby',
    quantBlend:'QUANT BLEND', poissonQuant:'POISSON QUANT · 10k SIMS', valuePick:'★ VALUE PICK',
    groqAgrees:'AGREES', groqDissent:'OWN OPINION',
    trackRecord:'📊 TRACK RECORD', picks_:'PICKS', hitRate:'HIT RATE', roi_:'ROI', brier:'BRIER',
    evaluated:'evaluated', open_:'open', perPick:'Per pick (1u stake)', lowerBetter:'Lower = better',
    bySource:'BY SOURCE', clvLabel:'★ CLOSING LINE VALUE',
    clvWin:'✓ You beat the closing line — long-term +EV.',
    clvLose:'Closing line beats you. System needs recalibration.',
    exportJson:'📥 Export JSON', resetBtn:'🗑️ Reset',
    confirmReset:'Really delete all picks and stats?',
    noAlt:'No reasonable alternative', connectionFailed:'AI connection lost.',
  },
  tr: {
    today:'Bugünkü Maçlar', matches:'Maç', topEvents:'ÖNE ÇIKANLAR',
    moreMatches:'DİĞER MAÇLAR', analyse:'AI Analiz', addTicket:'+ Kupon',
    agents:'Ajanlar', tickets:'Kuponlar', daily:'Günlük', bankroll:'Banka', info:'Bilgi',
    startAgents:'18 YAPAY ZEKA BAŞLAT', reanalyse:'Yeniden Analiz',
    running:'Dalga', of:'/', wave1:'DALGA 1 · VERİLER', wave2:'DALGA 2 · BAĞLAM',
    wave3:'DALGA 3 · RİSK', wave4:'DALGA 4 · KARAR',
    masterDecision:'MASTER KARAR', odds:'ORAN', confidence:'GÜVENİLİRLİK',
    safe:'GÜVENLİ', good:'DENGELİ', risk:'RİSKLİ',
    kiTickets:'AI KUPONLAR', myTicket:'BENIM KUPONUM', stats:'İSTATİSTİK',
    share:'Paylaş', track:'Takip Et', performance:'Performans',
    bankrollMgr:'Banka Yöneticisi', disclaimer:'⚠️ Yalnızca bilgi amaçlıdır. Sorumlu oynayın. 18+',
    noMatches:'Bu ligde maç yok', allLeagues:'Tümü',
    homeWin:'Ev Sahibi Kazanır', draw:'Beraberlik', awayWin:'Deplasman Kazanır',
    h2hHistory:'Karşılaşma Geçmişi', loading:'Yükleniyor...', error:'Hata',
    liveOdds:'CANLI ORANLAR', comparison:'Oran Karşılaştırma',
    weather:'HAVA DURUMU', analysing:'Analiz ediliyor...',
    kelly:'Kelly', bankrollGoal:'Hedef', stake:'Bahis',
    waiting:'bekliyor', generateFailed:'Kupon oluşturulamadı. Lütfen tekrar deneyin.',
    retry:'Tekrar Dene', generating:'AI kuponlar oluşturuyor...',
    headerSub:'9 AJAN · HAVA · KELLY',
    noTicket:'Henüz seçim yok', addFromToday:'"Bugün" → Analiz → "+Kupon"',
    useSlip:'Kuponu Kullan', newSlips:'Yeni Kuponlar',
    error_conn:'Bağlantı hatası.', waitingSuffix:'— bekliyor...',
    pendingWave:'Dalga', analyzing:'Analiz ediliyor',tabToday:'Bugün',tabAgents:'Ajanlar',tabTickets:'Kuponlar',tabTicker:'Canlı',tabBankroll:'Banka',tabInfo:'Bilgi',
    classic:'Klasik', halftime:'İlk Yarı', corners:'Köşe', edge:'Avantaj', mine:'Benim',
    classicDesc:'Güvenli · Dengeli · Riskli', halftimeDesc:'İY pazarları · Güvenli · Dengeli · Riskli', cornersDesc:'Köşe pazarları · Güvenli · Dengeli · Riskli',
    saved:'Kaydedildi', generateNew:'Yeniden Oluştur', generating2:'Oluşturuluyor…',
    edgeHunter:'Avantaj Avcısı', edgeHunterSub:'QUANT AVANTAJ · 10k SIMS/MAÇ',
    valuePicks:'DEĞERLİ SEÇİMLER', avgEdge:'Ø Avantaj', topToSlip:'En İyi 6 → Kupon',
    noEdgesFound:'Mevcut oranlarda ≥ {x}% avantaj yok.', loweringThreshold:'Eşiği düşür veya yenile.',
    manualSlip:'MANUEL KUPON', combo:'KOMBİNE', system:'SİSTEM', sysFehler:'K/N · HATAYA İZİN', sysVollett:'TAM KAPSAM · TÜM KOMBİNASYONLAR',
    needsPicks:'{n} seçim gerekli ({m} var)',
    overGoals:'Üst 2.5 Gol', underGoals:'Alt 2.5 Gol', bttsYes:'Karşılıklı Gol — Var', bttsNo:'Karşılıklı Gol — Yok',
    waveRunning:'Dalga {w}/4 çalışıyor', agentsAnalysing:'18 yapay zeka modeli maçı analiz ediyor — sonuç birazdan.',
    tapToStart:'Master karar için "18 Yapay Zeka Başlat" tıkla.',
    strongConsensus:'Güçlü konsensüs — {n}/9 ajan hemfikir',
    home_:'Ev', away_:'Dep', fresh:'dinç', tired:'yorgun', normalRest:'normal',
    lineupConfirmed:'Kadro onaylandı', lineupPending:'Kadro beklemede',
    cat_title_race:'Şampiyonluk Yarışı', cat_relegation_fight:'Küme Düşme', cat_relegation_threat:'Küme Düşme Riski',
    cat_european_chase:'Avrupa Yerleri', cat_champion_secure:'Şampiyonluk Güvende', cat_dead_rubber:'Önemsiz Maç',
    cat_midtable:'Orta Sıra', cat_derby:'Derbi',
    quantBlend:'QUANT KARIŞIM', poissonQuant:'POISSON QUANT · 10k SIMS', valuePick:'★ DEĞER SEÇİMİ',
    groqAgrees:'KATILIYOR', groqDissent:'KENDİ GÖRÜŞÜ',
    trackRecord:'📊 TAKİP KAYDI', picks_:'SEÇİMLER', hitRate:'İSABET ORANI', roi_:'ROI', brier:'BRIER',
    evaluated:'değerlendirildi', open_:'açık', perPick:'Seçim başına (1u bahis)', lowerBetter:'Düşük = daha iyi',
    bySource:'KAYNAK BAŞINA', clvLabel:'★ KAPANIŞ ORANI DEĞERİ',
    clvWin:'✓ Kapanış oranını yeniyorsun — uzun vadede +EV.',
    clvLose:'Kapanış oranı seni yeniyor. Sistem yeniden kalibrasyona ihtiyaç duyuyor.',
    exportJson:'📥 JSON İndir', resetBtn:'🗑️ Sıfırla',
    confirmReset:'Tüm seçimleri ve istatistikleri silinsin mi?',
    noAlt:'Mantıklı alternatif yok', connectionFailed:'Yapay zeka bağlantısı kesildi.',
  },
};
let currentLang = localStorage.getItem('fussball_lang') || 'de';
function t(key) { return (TRANSLATIONS[currentLang] || TRANSLATIONS.de)[key] || key; }
function setLang(l) { currentLang = l; localStorage.setItem('fussball_lang', l); }

// ─── AI SERVICE ───────────────────────────────────────────────
// Sprach-Direktive: zwingt LLM, alle freien Textfelder in der UI-Sprache zu liefern
function langDirective() {
  const lang = currentLang || 'de';
  if (lang === 'tr') return '\n\n⚠ KRITISCH: Antworte AUSSCHLIESSLICH auf TÜRKISCH (Türkçe). Tüm bet_label, reasoning, key_factor, label, alt_pick ve dissent metinleri Türkçe olmalıdır. JSON-Schlüssel bleiben Englisch, aber alle Werte (Strings) auf Türkisch.';
  if (lang === 'en') return '\n\n⚠ CRITICAL: Respond ENTIRELY in English. All bet_label, reasoning, key_factor, label, alt_pick and dissent text must be in English. JSON keys stay English, all string values in English.';
  return ''; // de = default, keine Direktive nötig
}

async function callAI(prompt, maxTokens = 2500) {
  prompt = prompt + langDirective();
  try {
    const res = await fetch('/api/deepseek', {
      method:'POST',
      headers:{'Content-Type':'application/json'},
      body:JSON.stringify({model:'deepseek-chat',messages:[{role:'user',content:prompt}],max_tokens:maxTokens,temperature:0.65})
    });
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const d = await res.json();
    return d.choices[0].message.content;
  } catch(e) { console.warn('DeepSeek→Claude fallback:',e.message); }
  return await window.claude.complete({messages:[{role:'user',content:prompt}]});
}

// Groq (Llama 3.3 70B) — Free Tier ~30 RPM, schneller als DeepSeek
async function callGroq(prompt, maxTokens = 2500) {
  prompt = prompt + langDirective();
  try {
    const res = await fetch('/api/groq', {
      method:'POST',
      headers:{'Content-Type':'application/json'},
      body:JSON.stringify({
        model: 'llama-3.3-70b-versatile',
        messages: [{ role: 'user', content: prompt }],
        max_tokens: maxTokens,
        temperature: 0.6,
      }),
    });
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const d = await res.json();
    return d.choices[0].message.content;
  } catch(e) { console.warn('Groq failed:', e.message); return null; }
}

// OpenRouter — universelle Schnittstelle, model-Param wählbar
async function callOpenRouter(model, prompt, maxTokens = 2000) {
  prompt = prompt + langDirective();
  try {
    const res = await fetch('/api/openrouter', {
      method:'POST',
      headers:{'Content-Type':'application/json'},
      body:JSON.stringify({
        model,
        messages: [{ role: 'user', content: prompt }],
        max_tokens: maxTokens,
        temperature: 0.6,
      }),
    });
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const d = await res.json();
    return d.choices?.[0]?.message?.content || null;
  } catch(e) { console.warn(`OpenRouter ${model} failed:`, e.message); return null; }
}

// Convenience: OpenAI GPT-OSS 120B via OpenRouter (3. Voice — andere Lab als DeepSeek/Llama)
async function callOpenAIOss(prompt, maxTokens = 2000) {
  return callOpenRouter('openai/gpt-oss-120b:free', prompt, maxTokens);
}
// Alias-Beibehaltung — falls später wieder Gemini verfügbar wird
const callGemini = callOpenAIOss;

// ─── WEATHER SERVICE ──────────────────────────────────────────
const weatherConditions = [
  {code:'clear',label:'Klar ☀️',wind:5,rain:0,temp:18,impact:'NEUTRAL'},
  {code:'cloudy',label:'Bewölkt ⛅',wind:12,rain:0,temp:14,impact:'NEUTRAL'},
  {code:'rainy',label:'Regen 🌧️',wind:18,rain:85,temp:10,impact:'LOW_SCORING'},
  {code:'stormy',label:'Sturm ⛈️',wind:34,rain:95,temp:8,impact:'CHAOTIC'},
  {code:'windy',label:'Windig 🌬️',wind:28,rain:10,temp:12,impact:'LOW_SCORING'},
  {code:'snow',label:'Schnee ❄️',wind:15,rain:60,temp:1,impact:'CHAOTIC'},
  {code:'humid',label:'Schwül 🌫️',wind:8,rain:20,temp:24,impact:'SLOWER_PACE'},
];
function getMatchWeather(matchId) {
  const seed = matchId.charCodeAt(matchId.length-1);
  return weatherConditions[seed % weatherConditions.length];
}
function getWeatherImpactColor(impact) {
  return impact==='NEUTRAL'?'#22ff88':impact==='LOW_SCORING'?'#5ee7ff':impact==='CHAOTIC'?'#ff5470':'#ffb648';
}

// ─── ODDS COMPARISON (Tipico / Bet365 / Bwin) ────────────────
function generateBookmakerOdds(baseOdds) {
  const spread = () => (Math.random() * 0.18 - 0.09);
  return {
    tipico: { home: +(baseOdds.home + spread()).toFixed(2), draw: +(baseOdds.draw + spread()).toFixed(2), away: +(baseOdds.away + spread()).toFixed(2) },
    bet365: { home: +(baseOdds.home + spread()).toFixed(2), draw: +(baseOdds.draw + spread()).toFixed(2), away: +(baseOdds.away + spread()).toFixed(2) },
    bwin:   { home: +(baseOdds.home + spread()).toFixed(2), draw: +(baseOdds.draw + spread()).toFixed(2), away: +(baseOdds.away + spread()).toFixed(2) },
    unibet: { home: +(baseOdds.home + spread()).toFixed(2), draw: +(baseOdds.draw + spread()).toFixed(2), away: +(baseOdds.away + spread()).toFixed(2) },
  };
}

// ─── H2H EXTENDED DATA ────────────────────────────────────────
const H2H_DATA = {
  m01: { results: [
    {date:'2024-03-14',home:'Eintracht',away:'Man City',score:'0-3',competition:'UCL'},
    {date:'2023-11-07',home:'Man City',away:'Eintracht',score:'3-1',competition:'UCL'},
    {date:'2022-04-13',home:'Eintracht',away:'Man City',score:'2-0',competition:'UEL'},
    {date:'2019-08-01',home:'Eintracht',away:'Man City',score:'0-2',competition:'Friendly'},
    {date:'2018-05-01',home:'Man City',away:'Eintracht',score:'1-1',competition:'UEL'},
  ], homeGoals:3, awayGoals:11, bttsCount:2, overCount:3 },
  m02: { results: [
    {date:'2024-02-22',home:'Leverkusen',away:'Roma',score:'2-0',competition:'UEL'},
    {date:'2023-12-01',home:'Roma',away:'Leverkusen',score:'1-0',competition:'Friendly'},
    {date:'2022-03-10',home:'Leverkusen',away:'Roma',score:'3-1',competition:'UEL'},
    {date:'2021-09-16',home:'Roma',away:'Leverkusen',score:'0-1',competition:'UEL'},
    {date:'2021-09-30',home:'Leverkusen',away:'Roma',score:'4-0',competition:'UEL'},
  ], homeGoals:10, awayGoals:2, bttsCount:1, overCount:3 },
  m08: { results: [
    {date:'2024-01-21',home:'Real',away:'Atletico',score:'3-1',competition:'LL'},
    {date:'2023-09-24',home:'Atletico',away:'Real',score:'3-1',competition:'LL'},
    {date:'2023-04-08',home:'Real',away:'Atletico',score:'1-0',competition:'LL'},
    {date:'2022-12-18',home:'Atletico',away:'Real',score:'2-1',competition:'LL'},
    {date:'2022-04-28',home:'Real',away:'Atletico',score:'2-1',competition:'LL'},
  ], homeGoals:10, awayGoals:8, bttsCount:3, overCount:3 },
};
function getH2H(matchId) {
  if (H2H_DATA[matchId]) return H2H_DATA[matchId];
  const seed = matchId.charCodeAt(matchId.length-1);
  return { results:[
    {date:'2024-01-15',home:'Team A',away:'Team B',score:'2-1',competition:'Liga'},
    {date:'2023-09-20',home:'Team B',away:'Team A',score:'0-0',competition:'Liga'},
    {date:'2023-04-05',home:'Team A',away:'Team B',score:'1-2',competition:'Liga'},
    {date:'2022-11-10',home:'Team B',away:'Team A',score:'3-0',competition:'Liga'},
    {date:'2022-03-22',home:'Team A',away:'Team B',score:'1-1',competition:'Liga'},
  ], homeGoals:seed%6+2, awayGoals:seed%4+1, bttsCount:seed%3+1, overCount:seed%3+2 };
}

// ─── FOOTBALL-DATA.ORG SERVICE ────────────────────────────────
const footballDataAPI = {
  baseURL:'/api/footballdata',
  getKey:()=>'PROXY',
  async fetch(path) {
    try {
      const res = await fetch(`${this.baseURL}${path.startsWith('/')?path:'/'+path}`);
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      return await res.json();
    } catch(e) { console.warn('football-data.org:',e.message); return null; }
  },
  async getTodayMatches() {
    const today = new Date().toISOString().split('T')[0];
    return await this.fetch(`/matches?dateFrom=${today}&dateTo=${today}`);
  }
};

// ─── 10 AGENTS (incl. WEATHER) ────────────────────────────────
// Extra-Kontext aus den Datenagenten (FATIGUE + LINEUP) für LLM-Prompts
function dataAgentContext(m) {
  if (!m) return '';
  const parts = [];
  if (m.fatigue?.status === 'ok') {
    const fH = m.fatigue.home, fA = m.fatigue.away;
    if (fH || fA) {
      parts.push(`FATIGUE: Heim=${fH?.daysRest??'?'}d Pause${fH?.midweekEuro?' (UEL Mittwoch!)':''} (${fH?.gameLoad??'?'}/14T), Gast=${fA?.daysRest??'?'}d Pause${fA?.midweekEuro?' (UEL Mittwoch!)':''} (${fA?.gameLoad??'?'}/14T)`);
    }
  }
  if (m.lineup?.confirmed) {
    const hStarters = (m.lineup.home || []).slice(0,11).map(p=>p.name).join(', ');
    const aStarters = (m.lineup.away || []).slice(0,11).map(p=>p.name).join(', ');
    parts.push(`LINEUP BESTÄTIGT (60min vor Anpfiff): Heim=[${hStarters}], Gast=[${aStarters}]`);
    if (m.lineup.formation?.home) parts.push(`Formationen: H=${m.lineup.formation.home}, A=${m.lineup.formation.away||'?'}`);
  } else if (m.lineup && m.lineup.status !== 'no_espn_id' && m.lineup.status !== 'unavailable') {
    parts.push('LINEUP: noch nicht bestätigt (vorläufige Analyse)');
  }
  if (m.referee?.status === 'ok') {
    parts.push(`REFEREE: ${m.referee.name} · ${m.referee.cards_per_match} Karten/Spiel · ${m.referee.penalties} Elfer in ${m.referee.games} Spielen`);
  }
  if (m.motivation?.status === 'ok') {
    const mh = m.motivation.home, ma = m.motivation.away;
    parts.push(`MOTIVATION: Heim=${mh.score}/100 (${mh.category}: ${mh.reason}) · Gast=${ma.score}/100 (${ma.category}: ${ma.reason}) · Gap=${m.motivation.gap>0?'+':''}${m.motivation.gap}`);
  }
  if (m.teamStats?.status === 'ok') {
    const h = m.teamStats.home, a = m.teamStats.away;
    if (h && a) parts.push(`FBREF SAISON: Heim xG/90=${h.xg90?.toFixed(2)} xGA/90=${h.xga90?.toFixed(2)} (${h.gp} Spiele) · Gast xG/90=${a.xg90?.toFixed(2)} xGA/90=${a.xga90?.toFixed(2)} (${a.gp} Spiele)`);
  }
  if (m.injuries?.status === 'ok') {
    const list = (arr) => (arr||[]).slice(0,5).map(p => `${p.name}${p.injury?` (${p.injury})`:''}${p.until?` bis ${p.until}`:''}`).join('; ');
    const hL = list(m.injuries.home), aL = list(m.injuries.away);
    if (hL || aL) parts.push(`INJURIES (Transfermarkt): Heim=[${hL || 'keine'}] · Gast=[${aL || 'keine'}]`);
  }
  return parts.length ? `\n[DATA-AGENTS] ${parts.join(' | ')}` : '';
}

const AGENTS = [
  {
    id:'scout',name:'SCOUT',title:'Spielbeobachter',icon:'🔍',
    color:'#5ee7ff',glow:'0 0 20px rgba(94,231,255,0.45)',
    specialty:'Form · H2H · Kader',wave:1,
    prompt:(m)=>`Du bist SCOUT, Elite-Fußball-Analyst für Form und H2H.
Spiel: ${m.home} vs ${m.away} (${m.league}, ${m.time} Uhr)
Form Heim (letzte 5): ${m.form.home.join('-')} | Auswärts: ${m.form.away.join('-')}
H2H letzte 5: ${m.h2h} | Tabellenplatz: ${m.home}(${m.homePos}.) vs ${m.away}(${m.awayPos}.)
Quoten: H${m.odds.home} X${m.odds.draw} A${m.odds.away} | BTTS:${m.btts.yes} | O2.5:${m.overUnder.o25}
Antworte NUR als JSON: {"recommendation":"HOME_WIN|DRAW|AWAY_WIN|OVER_25|UNDER_25|BTTS_YES","bet_label":"...","confidence":75,"reasoning":"2 Sätze","key_factor":"...","risk":"SAFE|GOOD|RISK"}`
  },
  {
    id:'stats',name:'STATS',title:'Quantitativer Analyst',icon:'📊',
    color:'#22ff88',glow:'0 0 20px rgba(34,255,136,0.45)',
    specialty:'xG · Possession · Schüsse',wave:1,
    prompt:(m)=>`Du bist STATS, quantitativer Fußball-Analyst.
Spiel: ${m.home} vs ${m.away} | xG: H${m.xG.home} A${m.xG.away}
Possession: H${m.possession.home}% A${m.possession.away}% | Ø Tore/Spiel: ${m.avgGoals}
Tabellenplatz: ${m.home}(${m.homePos}.) vs ${m.away}(${m.awayPos}.)
Quoten: H${m.odds.home} X${m.odds.draw} A${m.odds.away} | O2.5:${m.overUnder.o25} U2.5:${m.overUnder.u25}
Antworte NUR als JSON: {"recommendation":"HOME_WIN|DRAW|AWAY_WIN|OVER_25|UNDER_25|BTTS_YES","bet_label":"...","confidence":78,"reasoning":"2 Sätze","key_factor":"...","risk":"SAFE|GOOD|RISK"}`
  },
  {
    id:'injury',name:'INJURY',title:'Kader-Analyst',icon:'🏥',
    color:'#ff5470',glow:'0 0 20px rgba(255,84,112,0.4)',
    specialty:'Verletzungen · Sperren · Rotation',wave:1,
    prompt:(m)=>`Du bist INJURY, Experte für Kader-Verfügbarkeit.
Spiel: ${m.home} vs ${m.away} (${m.league}) | Wichtigkeit: ${m.importance||'Ligaspiel'}
Form: H${m.form.home.join('')} A${m.form.away.join('')} | Tabelle: ${m.homePos}. vs ${m.awayPos}.${dataAgentContext(m)}
Wenn Aufstellung bestätigt: nutze die ECHTE Liste, nicht generische Verletzungs-Annahmen. Prüfe ob Stammkräfte fehlen.
Antworte NUR als JSON: {"recommendation":"HOME_WIN|DRAW|AWAY_WIN|OVER_25|UNDER_25|BTTS_YES","bet_label":"...","confidence":65,"reasoning":"2 Sätze","key_factor":"...","risk":"SAFE|GOOD|RISK","rotation_risk":"HIGH|MEDIUM|LOW"}`
  },
  {
    id:'weather',name:'WEATHER',title:'Wetter-Analyst',icon:'🌦️',
    color:'#a8edff',glow:'0 0 20px rgba(168,237,255,0.45)',
    specialty:'Wetter · Rasen · Bedingungen',wave:1,
    prompt:(m,_,weather)=>`Du bist WEATHER, Spezialist für Wetterbedingungen im Fußball.
Spiel: ${m.home} vs ${m.away} (${m.league})
Wetterbedingungen: ${weather?.label||'Klar'} | Wind: ${weather?.wind||5}km/h | Regen: ${weather?.rain||0}%
Temperatur: ${weather?.temp||15}°C | Auswirkung: ${weather?.impact||'NEUTRAL'}
xG Heim: ${m.xG.home} | xG Auswärts: ${m.xG.away} | Ø Tore: ${m.avgGoals}

Analysiere: Wie beeinflussen die Bedingungen dieses Spiel? Wind→Flanken, Regen→Fehler, Kälte→Tempo
Antworte NUR als JSON: {"recommendation":"HOME_WIN|DRAW|AWAY_WIN|OVER_25|UNDER_25|BTTS_YES","bet_label":"...","confidence":68,"reasoning":"2 Sätze über Wettereinfluss","key_factor":"Wetterfaktor","risk":"SAFE|GOOD|RISK","weather_impact":"POSITIVE_HOME|POSITIVE_AWAY|LOW_SCORING|HIGH_SCORING|NEUTRAL"}`
  },
  {
    id:'tactical',name:'TACTICS',title:'Taktik-Experte',icon:'⚙️',
    color:'#a855f7',glow:'0 0 20px rgba(168,85,247,0.4)',
    specialty:'Formation · Pressing · Spielstil',wave:2,
    prompt:(m,w1)=>`Du bist TACTICS, Taktik-Analyse-Agent.
Spiel: ${m.home} vs ${m.away} | xG: H${m.xG.home} A${m.xG.away} | Possession: H${m.possession.home}% A${m.possession.away}%${dataAgentContext(m)}
Müder Gegner mit UEL-Mittwoch + Sonntags-Anpfiff = klares taktisches Risiko (Pressing-Resistenz sinkt). Formation aus LINEUP nutzen falls vorhanden.
Welle-1: ${w1}
Antworte NUR als JSON: {"recommendation":"HOME_WIN|DRAW|AWAY_WIN|OVER_25|UNDER_25|BTTS_YES","bet_label":"...","confidence":72,"reasoning":"2 Sätze","key_factor":"...","risk":"SAFE|GOOD|RISK","style_advantage":"HOME|AWAY|NEUTRAL"}`
  },
  {
    id:'mental',name:'MENTAL',title:'Psychologie-Agent',icon:'🔥',
    color:'#ffb648',glow:'0 0 20px rgba(255,182,72,0.4)',
    specialty:'Druck · Motivation · Moral',wave:2,
    prompt:(m,w1)=>`Du bist MENTAL, Psychologie & Motivations-Agent.
Spiel: ${m.home} vs ${m.away} | Wichtigkeit: ${m.importance||'Ligaspiel'}
Form: H${m.form.home.join('')} A${m.form.away.join('')} | H2H: ${m.h2h}${dataAgentContext(m)}
Hohe Spielbelastung (>3 Spiele/14T) bedeutet mentale Erschöpfung — wirkt sich primär in der 2.HZ aus.
Welle-1: ${w1}
Antworte NUR als JSON: {"recommendation":"HOME_WIN|DRAW|AWAY_WIN|OVER_25|UNDER_25|BTTS_YES","bet_label":"...","confidence":68,"reasoning":"2 Sätze","key_factor":"...","risk":"SAFE|GOOD|RISK","motivation":"HOME_HIGHER|AWAY_HIGHER|EQUAL"}`
  },
  {
    id:'value',name:'VALUE',title:'Quoten-Experte',icon:'💰',
    color:'#ffd700',glow:'0 0 20px rgba(255,215,0,0.4)',
    specialty:'Value · Implied Prob · Quoten',wave:2,
    prompt:(m,w1)=>`Du bist VALUE, Wettquoten-Value-Analyst.
Spiel: ${m.home} vs ${m.away}
Buchmacher: H${m.odds.home}(${(100/m.odds.home).toFixed(0)}%) X${m.odds.draw}(${(100/m.odds.draw).toFixed(0)}%) A${m.odds.away}(${(100/m.odds.away).toFixed(0)}%)
BTTS:${m.btts.yes} | O2.5:${m.overUnder.o25} | Welle-1: ${w1}
Antworte NUR als JSON: {"recommendation":"HOME_WIN|DRAW|AWAY_WIN|OVER_25|UNDER_25|BTTS_YES|HT_FT","bet_label":"...","confidence":73,"reasoning":"2 Sätze","key_factor":"...","risk":"SAFE|GOOD|RISK","value_rating":"HIGH|MEDIUM|LOW","true_prob":62}`
  },
  {
    id:'line',name:'LINE',title:'Quotenbewegung',icon:'📉',
    color:'#00e5ff',glow:'0 0 22px rgba(0,229,255,0.45)',
    specialty:'Sharp Money · Odds Movement · Steam',wave:2,
    prompt:(m,w1)=>`Du bist LINE, Spezialist für Quotenbewegungen und Sharp Money.
Spiel: ${m.home} vs ${m.away}
Eröffnungsquoten: H${m.lineMovement?.opening?.home||m.odds.home} X${m.lineMovement?.opening?.draw||m.odds.draw} A${m.lineMovement?.opening?.away||m.odds.away}
Aktuelle Quoten: H${m.odds.home} X${m.odds.draw} A${m.odds.away}
Sharp Money: ${m.lineMovement?.sharpMoney||'NEUTRAL'}
Welle-1: ${w1}
Antworte NUR als JSON: {"recommendation":"HOME_WIN|DRAW|AWAY_WIN|OVER_25|UNDER_25|BTTS_YES","bet_label":"...","confidence":74,"reasoning":"2 Sätze","key_factor":"Sharp Money","risk":"SAFE|GOOD|RISK","sharp_money":"HOME|AWAY|DRAW|GOALS|NO_GOALS","line_move":"SIGNIFICANT|MODERATE|MINIMAL","steam_move":false}`
  },
  {
    id:'risk',name:'RISK',title:'Risiko-Manager',icon:'🛡️',
    color:'#ff4fb3',glow:'0 0 20px rgba(255,79,179,0.45)',
    specialty:'Risiko · Bankroll · Kelly',wave:3,
    prompt:(m,allRecs)=>`Du bist RISK, Risikomanagement-Experte. SAFE=1.25-1.75,>80% | GOOD=1.75-2.80,65-80% | RISK=2.80+
Spiel: ${m.home} vs ${m.away}
Alle Agenten: ${JSON.stringify(allRecs)}
Antworte NUR als JSON: {"recommendation":"beste Empfehlung","bet_label":"...","confidence":75,"reasoning":"2 Sätze","key_factor":"...","risk":"SAFE|GOOD|RISK","stake_pct":3,"kelly_fraction":0.05}`
  },
  {
    id:'master',name:'MASTER',title:'KI-Synthesizer',icon:'👑',
    color:'#24daff',glow:'0 0 28px rgba(36,218,255,0.55)',
    specialty:'Synthese · Finale Entscheidung',wave:4,
    prompt:(m,all)=>`Du bist MASTER, finaler Synthese-Agent. 9 Agenten haben analysiert (inkl. WEATHER):
${JSON.stringify(all,null,1)}
Spiel: ${m.home} vs ${m.away} (${m.league})
WEATHER-Agent: Wetterbedingungen beachten! LINE-Agent: Sharp Money stark gewichten!
Antworte NUR als JSON: {"final_pick":"...","bet_label":"...","odds":1.85,"confidence":84,"reasoning":"3 Sätze","key_factor":"...","risk":"SAFE|GOOD|RISK","consensus":"STRONG|MODERATE|SPLIT","consensus_count":8,"stake_pct":3,"dissent":"...","ticket_worthy":true,"alt_pick":"..."}`
  }
];

// ─── LEAGUES ──────────────────────────────────────────────────
const LEAGUES = {
  BL:{name:'Bundesliga',flag:'🇩🇪',color:'#e30614',fdCode:'BL1'},
  PL:{name:'Premier League',flag:'🏴󠁧󠁢󠁥󠁮󠁧󠁿',color:'#3d195b',fdCode:'PL'},
  LL:{name:'La Liga',flag:'🇪🇸',color:'#ee8707',fdCode:'PD'},
  SA:{name:'Serie A',flag:'🇮🇹',color:'#1a56c4',fdCode:'SA'},
  L1:{name:'Ligue 1',flag:'🇫🇷',color:'#0055a4',fdCode:'FL1'},
  ERE:{name:'Eredivisie',flag:'🇳🇱',color:'#ff6600',fdCode:'DED'},
  SL:{name:'Super League',flag:'🇨🇭',color:'#ff0000',fdCode:null},
  JPL:{name:'Jupiler Pro League',flag:'🇧🇪',color:'#f6a800',fdCode:null},
  SUP:{name:'Süper Lig',flag:'🇹🇷',color:'#e30a17',fdCode:null},
  PRI:{name:'Primeira Liga',flag:'🇵🇹',color:'#006600',fdCode:'PPL'},
  UCL:{name:'Champions League',flag:'⭐',color:'#001489',fdCode:'CL'},
  UEL:{name:'Europa League',flag:'🌐',color:'#ff6b35',fdCode:'EL'},
  ECL:{name:'Conference League',flag:'🌍',color:'#00c853',fdCode:null},
};

// ─── AUTO-DATE: get today's date string ───────────────────────
function getTodayLabel() {
  const d = new Date();
  const days = ['SO','MO','DI','MI','DO','FR','SA'];
  const months = ['JAN','FEB','MRZ','APR','MAI','JUN','JUL','AUG','SEP','OKT','NOV','DEZ'];
  return `${days[d.getDay()]}. ${d.getDate()}. ${months[d.getMonth()]} ${d.getFullYear()}`;
}

// ─── MATCHES ──────────────────────────────────────────────────
const MATCHES_TODAY = [
  {id:'m01',leagueKey:'UEL',home:'Eintracht Frankfurt',away:'Manchester City',time:'21:00',importance:'SF HINSPIEL',
    odds:{home:3.20,draw:3.50,away:2.15},htOdds:{hh:8.5,hd:6.0,ha:4.2,dh:7.0,dd:11.0,da:8.0,ah:12.0,ad:14.0,aa:4.8},
    btts:{yes:1.68,no:2.10},overUnder:{o25:1.78,u25:2.00,o35:2.90,u35:1.42},
    form:{home:['W','D','W','W','L'],away:['W','W','W','W','D']},homePos:4,awayPos:1,
    h2h:'1W 1D 3L',xG:{home:1.4,away:2.1},avgGoals:2.9,possession:{home:42,away:58},
    handicap:{line:-0.5,homeOdds:4.50,awayOdds:1.65},
    lineMovement:{opening:{home:3.40,draw:3.55,away:2.05},homeMove:-5.9,awayMove:4.9,sharpMoney:'AWAY',steamMove:false}},
  {id:'m02',leagueKey:'UEL',home:'Bayer Leverkusen',away:'AS Roma',time:'21:00',importance:'SF HINSPIEL',
    odds:{home:1.95,draw:3.60,away:3.80},htOdds:{hh:3.8,hd:3.2,ha:7.5,dh:6.5,dd:9.0,da:11.0,ah:9.5,ad:8.5,aa:5.2},
    btts:{yes:1.75,no:2.00},overUnder:{o25:1.90,u25:1.90,o35:3.00,u35:1.38},
    form:{home:['W','W','W','D','W'],away:['W','L','W','W','W']},homePos:2,awayPos:6,
    h2h:'3W 1D 1L',xG:{home:2.0,away:1.3},avgGoals:2.7,possession:{home:56,away:44},
    handicap:{line:-0.5,homeOdds:2.80,awayOdds:1.40},
    lineMovement:{opening:{home:2.10,draw:3.60,away:3.60},homeMove:-7.1,awayMove:5.6,sharpMoney:'HOME',steamMove:true}},
  {id:'m03',leagueKey:'ECL',home:'Chelsea',away:'Fenerbahçe',time:'21:00',importance:'SF HINSPIEL',
    odds:{home:1.70,draw:3.75,away:4.80},htOdds:{hh:3.0,hd:3.4,ha:10.0,dh:8.0,dd:9.5,da:14.0,ah:13.0,ad:12.0,aa:6.0},
    btts:{yes:1.85,no:1.90},overUnder:{o25:1.95,u25:1.85,o35:3.20,u35:1.35},
    form:{home:['W','W','D','W','W'],away:['W','W','L','D','W']},homePos:3,awayPos:2,
    h2h:'2W 2D 1L',xG:{home:1.9,away:1.1},avgGoals:2.5,possession:{home:60,away:40},
    handicap:{line:-0.5,homeOdds:2.30,awayOdds:1.58},
    lineMovement:{opening:{home:1.80,draw:3.70,away:4.50},homeMove:-5.6,awayMove:6.7,sharpMoney:'HOME',steamMove:false}},
  {id:'m04',leagueKey:'BL',home:'Bayern München',away:'RB Leipzig',time:'20:30',importance:null,
    odds:{home:1.62,draw:4.10,away:5.00},htOdds:{hh:2.8,hd:3.2,ha:11.0,dh:9.0,dd:9.5,da:15.0,ah:14.0,ad:13.0,aa:6.5},
    btts:{yes:1.72,no:2.05},overUnder:{o25:1.65,u25:2.20,o35:2.50,u35:1.52},
    form:{home:['W','W','W','W','D'],away:['W','L','D','W','W']},homePos:1,awayPos:3,
    h2h:'4W 0D 1L',xG:{home:2.4,away:1.5},avgGoals:3.2,possession:{home:62,away:38},
    handicap:{line:-1.5,homeOdds:2.40,awayOdds:1.58},
    lineMovement:{opening:{home:1.70,draw:4.00,away:4.80},homeMove:-4.7,awayMove:4.2,sharpMoney:'HOME',steamMove:true}},
  {id:'m05',leagueKey:'BL',home:'Borussia Dortmund',away:'VfB Stuttgart',time:'18:30',importance:null,
    odds:{home:1.85,draw:3.70,away:4.20},htOdds:{hh:3.4,hd:3.3,ha:8.5,dh:7.0,dd:9.0,da:12.0,ah:11.5,ad:11.0,aa:5.5},
    btts:{yes:1.78,no:1.98},overUnder:{o25:1.80,u25:1.98,o35:2.80,u35:1.40},
    form:{home:['W','D','W','L','W'],away:['D','W','W','D','L']},homePos:3,awayPos:5,
    h2h:'3W 1D 1L',xG:{home:1.9,away:1.4},avgGoals:2.8,possession:{home:54,away:46},
    handicap:{line:-0.5,homeOdds:2.60,awayOdds:1.50},
    lineMovement:{opening:{home:1.90,draw:3.70,away:4.00},homeMove:-2.6,awayMove:5.0,sharpMoney:'NEUTRAL',steamMove:false}},
  {id:'m06',leagueKey:'PL',home:'Arsenal',away:'Newcastle Utd',time:'21:15',importance:null,
    odds:{home:1.88,draw:3.70,away:4.00},htOdds:{hh:3.5,hd:3.3,ha:8.0,dh:7.5,dd:9.5,da:12.0,ah:11.0,ad:11.5,aa:5.5},
    btts:{yes:1.80,no:1.95},overUnder:{o25:1.88,u25:1.92,o35:3.10,u35:1.36},
    form:{home:['W','D','W','W','L'],away:['W','W','D','W','W']},homePos:2,awayPos:4,
    h2h:'3W 1D 1L',xG:{home:1.8,away:1.6},avgGoals:2.6,possession:{home:55,away:45},
    handicap:{line:-0.5,homeOdds:2.70,awayOdds:1.47},
    lineMovement:{opening:{home:1.95,draw:3.65,away:3.80},homeMove:-3.6,awayMove:5.3,sharpMoney:'HOME',steamMove:false}},
  {id:'m07',leagueKey:'PL',home:'Liverpool',away:'Tottenham',time:'20:00',importance:null,
    odds:{home:1.72,draw:3.90,away:4.60},htOdds:{hh:3.0,hd:3.5,ha:9.5,dh:8.5,dd:9.5,da:14.0,ah:13.5,ad:12.5,aa:6.5},
    btts:{yes:1.75,no:2.00},overUnder:{o25:1.72,u25:2.10,o35:2.70,u35:1.46},
    form:{home:['W','W','D','W','W'],away:['L','W','D','W','L']},homePos:1,awayPos:8,
    h2h:'4W 1D 0L',xG:{home:2.2,away:1.3},avgGoals:3.1,possession:{home:60,away:40},
    handicap:{line:-1.5,homeOdds:2.50,awayOdds:1.55},
    lineMovement:{opening:{home:1.80,draw:3.85,away:4.40},homeMove:-4.4,awayMove:4.5,sharpMoney:'GOALS',steamMove:false}},
  {id:'m08',leagueKey:'LL',home:'Real Madrid',away:'Atlético Madrid',time:'21:00',importance:'DERBY',
    odds:{home:2.10,draw:3.30,away:3.40},htOdds:{hh:4.2,hd:3.1,ha:5.8,dh:6.2,dd:8.5,da:8.0,ah:8.5,ad:9.0,aa:4.5},
    btts:{yes:1.78,no:2.00},overUnder:{o25:2.00,u25:1.80,o35:3.50,u35:1.30},
    form:{home:['W','W','L','W','W'],away:['W','W','W','D','W']},homePos:1,awayPos:2,
    h2h:'2W 2D 1L',xG:{home:1.7,away:1.8},avgGoals:2.3,possession:{home:52,away:48},
    handicap:{line:0,homeOdds:2.20,awayOdds:2.20},
    lineMovement:{opening:{home:2.20,draw:3.25,away:3.25},homeMove:-4.5,awayMove:4.6,sharpMoney:'DRAW',steamMove:false}},
  {id:'m09',leagueKey:'LL',home:'FC Barcelona',away:'Valencia CF',time:'19:00',importance:null,
    odds:{home:1.45,draw:4.50,away:6.50},htOdds:{hh:2.4,hd:3.8,ha:14.0,dh:11.0,dd:10.0,da:20.0,ah:18.0,ad:16.0,aa:8.0},
    btts:{yes:1.90,no:1.85},overUnder:{o25:1.60,u25:2.30,o35:2.40,u35:1.55},
    form:{home:['W','W','W','D','W'],away:['L','D','W','L','D']},homePos:2,awayPos:9,
    h2h:'5W 0D 0L',xG:{home:2.5,away:0.9},avgGoals:2.8,possession:{home:68,away:32},
    handicap:{line:-1.5,homeOdds:2.20,awayOdds:1.65},
    lineMovement:{opening:{home:1.50,draw:4.40,away:6.00},homeMove:-3.3,awayMove:8.3,sharpMoney:'HOME',steamMove:false}},
  {id:'m10',leagueKey:'SA',home:'Inter Milan',away:'Juventus',time:'20:45',importance:'DERBY D\'ITALIA',
    odds:{home:2.05,draw:3.40,away:3.50},htOdds:{hh:4.0,hd:3.2,ha:6.0,dh:6.0,dd:8.5,da:9.0,ah:9.0,ad:9.0,aa:5.0},
    btts:{yes:1.75,no:2.00},overUnder:{o25:1.95,u25:1.85,o35:3.20,u35:1.35},
    form:{home:['W','D','W','W','D'],away:['W','W','L','W','W']},homePos:1,awayPos:3,
    h2h:'2W 2D 1L',xG:{home:1.9,away:1.7},avgGoals:2.4,possession:{home:54,away:46},
    handicap:{line:0,homeOdds:2.20,awayOdds:2.10},
    lineMovement:{opening:{home:2.15,draw:3.40,away:3.30},homeMove:-4.7,awayMove:6.1,sharpMoney:'HOME',steamMove:true}},
  {id:'m11',leagueKey:'SA',home:'AC Milan',away:'Napoli',time:'18:00',importance:null,
    odds:{home:2.20,draw:3.30,away:3.20},htOdds:{hh:4.5,hd:3.3,ha:5.8,dh:6.5,dd:8.5,da:8.5,ah:8.5,ad:9.0,aa:5.0},
    btts:{yes:1.82,no:1.92},overUnder:{o25:1.95,u25:1.85,o35:3.10,u35:1.36},
    form:{home:['D','W','W','L','W'],away:['W','W','D','W','W']},homePos:5,awayPos:2,
    h2h:'1W 2D 2L',xG:{home:1.5,away:1.9},avgGoals:2.5,possession:{home:48,away:52},
    handicap:{line:0,homeOdds:2.25,awayOdds:2.15},
    lineMovement:{opening:{home:2.30,draw:3.25,away:3.00},homeMove:-4.3,awayMove:6.7,sharpMoney:'AWAY',steamMove:false}},
  {id:'m12',leagueKey:'L1',home:'Paris Saint-Germain',away:'Olympique Lyon',time:'21:05',importance:null,
    odds:{home:1.40,draw:4.80,away:7.00},htOdds:{hh:2.2,hd:4.0,ha:16.0,dh:12.0,dd:10.0,da:22.0,ah:20.0,ad:18.0,aa:9.0},
    btts:{yes:1.95,no:1.82},overUnder:{o25:1.62,u25:2.25,o35:2.35,u35:1.58},
    form:{home:['W','W','W','W','W'],away:['L','W','D','W','L']},homePos:1,awayPos:7,
    h2h:'5W 0D 0L',xG:{home:2.6,away:1.0},avgGoals:2.9,possession:{home:65,away:35},
    handicap:{line:-2,homeOdds:2.10,awayOdds:1.72},
    lineMovement:{opening:{home:1.45,draw:4.70,away:6.50},homeMove:-3.4,awayMove:7.7,sharpMoney:'HOME',steamMove:false}},
  {id:'m13',leagueKey:'L1',home:'Marseille',away:'Monaco',time:'17:00',importance:null,
    odds:{home:2.30,draw:3.20,away:3.10},htOdds:{hh:4.8,hd:3.2,ha:5.5,dh:6.5,dd:8.5,da:8.0,ah:8.0,ad:9.0,aa:4.8},
    btts:{yes:1.70,no:2.10},overUnder:{o25:1.78,u25:2.00,o35:2.80,u35:1.42},
    form:{home:['W','L','W','D','W'],away:['W','W','W','L','W']},homePos:4,awayPos:3,
    h2h:'2W 1D 2L',xG:{home:1.6,away:1.8},avgGoals:2.9,possession:{home:49,away:51},
    handicap:{line:0,homeOdds:2.40,awayOdds:2.00},
    lineMovement:{opening:{home:2.40,draw:3.15,away:2.95},homeMove:-4.2,awayMove:5.1,sharpMoney:'AWAY',steamMove:false}},
  {id:'m14',leagueKey:'ERE',home:'Ajax Amsterdam',away:'PSV Eindhoven',time:'18:45',importance:'TOPPER',
    odds:{home:2.40,draw:3.20,away:2.90},htOdds:{hh:5.0,hd:3.2,ha:5.2,dh:6.5,dd:8.5,da:7.5,ah:7.5,ad:8.5,aa:4.8},
    btts:{yes:1.68,no:2.12},overUnder:{o25:1.72,u25:2.10,o35:2.65,u35:1.48},
    form:{home:['L','W','D','W','W'],away:['W','W','W','W','D']},homePos:3,awayPos:1,
    h2h:'2W 1D 2L',xG:{home:1.7,away:2.0},avgGoals:3.1,possession:{home:55,away:45},
    handicap:{line:0,homeOdds:2.55,awayOdds:1.95},
    lineMovement:{opening:{home:2.60,draw:3.15,away:2.70},homeMove:-7.7,awayMove:7.4,sharpMoney:'HOME',steamMove:true}},
  {id:'m15',leagueKey:'JPL',home:'Club Brugge',away:'Anderlecht',time:'16:00',importance:'DERBY',
    odds:{home:2.00,draw:3.40,away:3.60},htOdds:{hh:3.8,hd:3.3,ha:7.0,dh:6.5,dd:9.0,da:10.0,ah:10.0,ad:9.5,aa:5.5},
    btts:{yes:1.72,no:2.06},overUnder:{o25:1.80,u25:1.98,o35:2.85,u35:1.40},
    form:{home:['W','W','D','W','L'],away:['W','D','W','W','W']},homePos:1,awayPos:2,
    h2h:'3W 1D 1L',xG:{home:1.8,away:1.5},avgGoals:2.7,possession:{home:52,away:48},
    handicap:{line:-0.5,homeOdds:3.00,awayOdds:1.52},
    lineMovement:{opening:{home:2.10,draw:3.35,away:3.40},homeMove:-4.8,awayMove:5.9,sharpMoney:'HOME',steamMove:false}},
  {id:'m16',leagueKey:'SUP',home:'Galatasaray',away:'Fenerbahçe',time:'19:00',importance:'SÜPER DERBY',
    odds:{home:2.20,draw:3.10,away:3.30},htOdds:{hh:4.5,hd:3.1,ha:6.0,dh:6.5,dd:8.5,da:9.0,ah:9.0,ad:9.5,aa:5.0},
    btts:{yes:1.75,no:2.00},overUnder:{o25:1.85,u25:1.95,o35:3.00,u35:1.38},
    form:{home:['W','W','D','W','W'],away:['W','W','W','D','W']},homePos:1,awayPos:2,
    h2h:'2W 2D 1L',xG:{home:1.8,away:1.7},avgGoals:2.6,possession:{home:53,away:47},
    handicap:{line:0,homeOdds:2.30,awayOdds:2.10},
    lineMovement:{opening:{home:2.30,draw:3.10,away:3.10},homeMove:-4.3,awayMove:6.5,sharpMoney:'HOME',steamMove:false}},
  {id:'m17',leagueKey:'PRI',home:'SL Benfica',away:'FC Porto',time:'20:30',importance:'O CLÁSSICO',
    odds:{home:1.95,draw:3.50,away:3.80},htOdds:{hh:3.8,hd:3.3,ha:7.5,dh:6.5,dd:9.0,da:11.0,ah:11.0,ad:10.0,aa:5.5},
    btts:{yes:1.80,no:1.95},overUnder:{o25:1.88,u25:1.92,o35:3.00,u35:1.38},
    form:{home:['W','W','D','W','D'],away:['W','W','W','L','W']},homePos:2,awayPos:1,
    h2h:'2W 2D 1L',xG:{home:1.7,away:1.6},avgGoals:2.5,possession:{home:54,away:46},
    handicap:{line:0,homeOdds:2.20,awayOdds:2.20},
    lineMovement:{opening:{home:2.05,draw:3.45,away:3.60},homeMove:-4.9,awayMove:5.6,sharpMoney:'HOME',steamMove:false}},
  {id:'m18',leagueKey:'SL',home:'FC Basel',away:'Young Boys',time:'16:30',importance:null,
    odds:{home:2.50,draw:3.10,away:2.75},htOdds:{hh:5.5,hd:3.2,ha:5.0,dh:7.0,dd:9.0,da:7.5,ah:7.5,ad:8.5,aa:4.5},
    btts:{yes:1.75,no:2.00},overUnder:{o25:1.85,u25:1.93,o35:3.00,u35:1.38},
    form:{home:['D','W','L','W','W'],away:['W','D','W','W','L']},homePos:4,awayPos:1,
    h2h:'2W 1D 2L',xG:{home:1.5,away:1.7},avgGoals:2.6,possession:{home:47,away:53},
    handicap:{line:0,homeOdds:2.60,awayOdds:1.90},
    lineMovement:{opening:{home:2.60,draw:3.05,away:2.60},homeMove:-3.8,awayMove:5.8,sharpMoney:'AWAY',steamMove:false}},
];

// ─── Enrich matches ───────────────────────────────────────────
MATCHES_TODAY.forEach(m => {
  const lg = LEAGUES[m.leagueKey] || {};
  m.league = lg.name || m.leagueKey;
  m.leagueShort = m.leagueKey;
  m.leagueColor = lg.color || '#22ff88';
  m.leagueFlag = lg.flag || '⚽';
  m.weather = getMatchWeather(m.id);
  m.bookmakerOdds = generateBookmakerOdds(m.odds);
  m.h2hData = getH2H(m.id);
});

// ─── UTILS ────────────────────────────────────────────────────
function getRiskColor(r)       { return r==='SAFE'?'#22ff88':r==='GOOD'?'#ffb648':'#ff5470'; }
function getRiskLabel(r)       { return r==='SAFE'?'SAFE':r==='GOOD'?'BALANCED':'RISK'; }
function getRiskIcon(r)        { return r==='SAFE'?'🛡️':r==='GOOD'?'⚡':'🔥'; }
function formatOdds(o)         { return typeof o==='number'?o.toFixed(2):String(o); }
function getConsensusColor(c)  { return c==='STRONG'?'#22ff88':c==='MODERATE'?'#ffb648':'#ff5470'; }
function getLineColor(sm)      { return sm==='HOME'?'#22ff88':sm==='AWAY'?'#ff5470':sm==='GOALS'?'#ffb648':sm==='DRAW'?'#5ee7ff':'rgba(255,255,255,0.3)'; }

// ─── PERFORMANCE STORE ────────────────────────────────────────
const perfStore = {
  KEY:'fussball_ai_bets',
  get(){ try{return JSON.parse(localStorage.getItem(this.KEY)||'[]');}catch{return[];} },
  save(bets){ localStorage.setItem(this.KEY,JSON.stringify(bets)); },
  addBet(bet){ const bets=this.get(); bets.unshift({...bet,id:Date.now(),date:new Date().toISOString().split('T')[0],status:'pending'}); this.save(bets); return bets; },
  settle(id,won){ const bets=this.get().map(b=>b.id===id?{...b,status:won?'won':'lost',profit:won?b.stake*b.odds-b.stake:-b.stake}:b); this.save(bets); return bets; },
  clear(){ this.save([]); },
  stats(bets){
    const settled=bets.filter(b=>b.status!=='pending');
    const won=settled.filter(b=>b.status==='won');
    const totalStake=settled.reduce((a,b)=>a+(b.stake||10),0);
    const totalReturn=won.reduce((a,b)=>a+(b.stake||10)*b.odds,0);
    const profit=totalReturn-totalStake;
    const roi=totalStake>0?(profit/totalStake*100):0;
    const streak=(()=>{ let s=0; for(const b of settled){if(b.status==='won')s++;else break;} return s; })();
    // Liga breakdown
    const byLeague={};
    settled.forEach(b=>{
      const l=b.league||'?';
      if(!byLeague[l]) byLeague[l]={total:0,won:0,profit:0};
      byLeague[l].total++;
      if(b.status==='won'){ byLeague[l].won++; byLeague[l].profit+=(b.stake||10)*b.odds-(b.stake||10); }
      else { byLeague[l].profit-=(b.stake||10); }
    });
    return{total:settled.length,won:won.length,lost:settled.length-won.length,hitRate:settled.length>0?Math.round(won.length/settled.length*100):0,profit:profit.toFixed(2),roi:roi.toFixed(1),streak,byLeague};
  }
};

// ─── BANKROLL STORE ───────────────────────────────────────────
const bankrollStore = {
  KEY:'fussball_bankroll',
  get(){ try{return JSON.parse(localStorage.getItem(this.KEY)||'null');}catch{return null;} },
  save(data){ localStorage.setItem(this.KEY,JSON.stringify(data)); },
  init(initial,goal){ const d={initial,current:initial,goal,history:[{date:new Date().toISOString().split('T')[0],balance:initial,note:'Start'}]}; this.save(d); return d; },
  update(amount,note){ const d=this.get(); if(!d)return; d.current+=amount; d.history.unshift({date:new Date().toISOString().split('T')[0],balance:d.current,note}); this.save(d); return d; },
  reset(){ this.save(null); },
};

Object.assign(window, {
  callAI, footballDataAPI, AGENTS, LEAGUES, MATCHES_TODAY,
  getRiskColor, getRiskLabel, getRiskIcon, formatOdds, getConsensusColor, getLineColor,
  perfStore, bankrollStore,
  t, setLang, currentLang, TRANSLATIONS, getTodayLabel,
  getMatchWeather, getWeatherImpactColor, getH2H, generateBookmakerOdds,
});
