// Puan sistemi — gamification.jsx
// 950h toplam çalışma → +14 puan (58 → 72)
// Ay katsayıları (4 eşit dilim, Nisan 24 → Ağu 26):
//   ay1 1.00x, ay2 1.28x, ay3 1.60x, ay4 2.00x
// Efektif saat: gün_saati × ayKatsayı
// Puan = (14 / toplam_efektif_saat) × efektif_saat

const GAMIFY = (() => {
  const PLAN_START_STR = '2026-04-25';
  const PLAN_END_STR   = '2026-08-25'; // TUS günü hariç son çalışma günü
  const TUS_STR        = '2026-08-26';

  const START_SCORE    = 58;
  const TARGET_SCORE   = 72;
  const DELTA_SCORE    = TARGET_SCORE - START_SCORE; // 14
  const TOTAL_HOURS    = 950; // hedef çalışma saati

  // 4 eşit ay dilimi — takvim ayı değil, ~30-gün blokları (başlangıç 25 Nis)
  // 25 Nis → 24 May | 25 May → 23 Haz | 24 Haz → 23 Tem | 24 Tem → 25 Ağu
  const MONTH_BOUNDS = [
    { idx: 0, start: '2026-04-25', end: '2026-05-24', factor: 1.00, label: 'Ay 1' },
    { idx: 1, start: '2026-05-25', end: '2026-06-23', factor: 1.28, label: 'Ay 2' },
    { idx: 2, start: '2026-06-24', end: '2026-07-23', factor: 1.60, label: 'Ay 3' },
    { idx: 3, start: '2026-07-24', end: '2026-08-25', factor: 2.00, label: 'Ay 4' },
  ];

  // Günlük ortalama saat = 950 / toplam gün
  function planDayCount() {
    const s = new Date(PLAN_START_STR);
    const e = new Date(PLAN_END_STR);
    return Math.round((e - s) / 86400000) + 1;
  }

  // Efektif toplam saat: her günü 950/toplamGün × aykatsayı ile ağırlıklandır
  // Ancak bloklar bazlı puan üretimi istiyoruz, bu yüzden farklı yaklaşım:
  // toplam_efektif_hours = Σ (günün planlı_saati × ayKatsayı)
  // Puan başına saat (efektif) = DELTA_SCORE / toplam_efektif_hours
  // Her tıklanan blok 1 saat → o günün ay katsayısı × (DELTA_SCORE / TOTAL_EFFECTIVE)

  function monthFactorFor(ds) {
    for (const m of MONTH_BOUNDS) {
      if (ds >= m.start && ds <= m.end) return m;
    }
    // plan dışı gün — Ay 1 katsayısı
    return MONTH_BOUNDS[0];
  }

  // state.days üzerinden toplam efektif saati hesapla
  function computeTotalEffective(days) {
    let total = 0;
    for (const ds in days) {
      if (ds >= PLAN_START_STR && ds <= PLAN_END_STR) {
        const d = days[ds];
        const all = [...(d.morning || []), ...(d.evening || [])];
        // İSG, TUS, OFF günlerini dahil etme
        if (all.some(t => t.kind === 'tus' || t.kind === 'off' || t.kind === 'exam')) continue;
        const hrs = all.filter(t => !t.locked).reduce((a, t) => a + (t.hours || 0), 0);
        const mf = monthFactorFor(ds);
        total += hrs * mf.factor;
      }
    }
    return total;
  }

  // Bir günün 1 saatinin kaç puan getirdiğini hesapla
  function pointsPerHour(ds, totalEffective) {
    const mf = monthFactorFor(ds);
    if (totalEffective <= 0) return 0;
    return (DELTA_SCORE / totalEffective) * mf.factor;
  }

  // Bir günün toplam puan potansiyeli (tüm bloklar tamamlanırsa)
  function dayMaxPoints(ds, days, totalEffective) {
    const d = days[ds];
    if (!d) return 0;
    const all = [...(d.morning || []), ...(d.evening || [])];
    if (all.some(t => t.kind === 'tus' || t.kind === 'off' || t.kind === 'exam')) return 0;
    const hrs = all.filter(t => !t.locked).reduce((a, t) => a + (t.hours || 0), 0);
    const planned = Math.min(8, Math.max(4, Math.round(hrs)));
    return planned * pointsPerHour(ds, totalEffective);
  }

  // Günün şu ana kadar kazanılan puanı (hourBlocks bazlı)
  function dayEarnedPoints(ds, days, totalEffective) {
    const d = days[ds];
    if (!d || !d.hourBlocks) return 0;
    const doneBlocks = d.hourBlocks.filter(Boolean).length;
    return doneBlocks * pointsPerHour(ds, totalEffective);
  }

  // Bir günün kaçırılan puanı
  function dayMissedPoints(ds, days, totalEffective, todayStr) {
    if (ds >= todayStr) return 0; // gelecek/bugün henüz kaçırılmadı
    const d = days[ds];
    if (!d) return 0;
    const all = [...(d.morning || []), ...(d.evening || [])];
    if (all.some(t => t.kind === 'tus' || t.kind === 'off' || t.kind === 'exam')) return 0;
    const max = dayMaxPoints(ds, days, totalEffective);
    const earned = dayEarnedPoints(ds, days, totalEffective);
    return Math.max(0, max - earned);
  }

  // Tüm günlerin toplam kazanılmış puanı
  function totalEarned(days, totalEffective) {
    let t = 0;
    for (const ds in days) {
      t += dayEarnedPoints(ds, days, totalEffective);
    }
    return t;
  }

  // Bugüne kadar olması gereken tahmini puan (lineer hedef)
  function expectedByDate(targetDs, days, totalEffective) {
    let t = 0;
    for (const ds in days) {
      if (ds <= targetDs && ds >= PLAN_START_STR && ds <= PLAN_END_STR) {
        t += dayMaxPoints(ds, days, totalEffective);
      }
    }
    return t;
  }

  // Kaçırılan görev saatleri (ders bazlı) — görev.hours > tamamlanan kısım
  // Kaçırılanları "done değil ve tarihi geçmiş" tasklardan topla
  function missedByLesson(days, todayStr) {
    const bucket = {}; // lessonTag → { title, color, missedH, days: [] }
    for (const ds in days) {
      if (ds >= todayStr) continue;
      const d = days[ds];
      if (!d) continue;
      const all = [...(d.morning || []), ...(d.evening || [])];
      if (all.some(t => t.kind === 'tus' || t.kind === 'off' || t.kind === 'exam')) continue;

      // Günün hourBlocks done oranını kullan — tasklara prorata dağıt
      const planned = Math.min(8, Math.max(4, Math.round(
        all.filter(t => !t.locked).reduce((a, t) => a + (t.hours || 0), 0)
      )));
      const doneBlocks = (d.hourBlocks || []).filter(Boolean).length;
      const doneRatio = planned > 0 ? doneBlocks / planned : 0;

      all.filter(t => !t.locked).forEach(t => {
        const missed = (t.hours || 0) * (1 - doneRatio);
        if (missed < 0.05) return;
        const key = t.lessonTag || t.tag || t.title;
        if (!bucket[key]) {
          bucket[key] = {
            key,
            title: t.lessonTitle || t.title.split('·')[0].trim(),
            color: t.color || '#c9c2b5',
            missedH: 0,
            days: [],
          };
        }
        bucket[key].missedH += missed;
        bucket[key].days.push({ ds, title: t.title, hours: missed });
      });
    }
    return Object.values(bucket).sort((a, b) => b.missedH - a.missedH);
  }

  // Puan milestones (ödüller) — eskisi korunuyor
  const MILESTONES = [
    { score: 60, label: 'İlk 2 puan', note: 'Hız aldın. Devam.' },
    { score: 63, label: 'Yarı yolda', note: '5/14. Ritim oturdu.' },
    { score: 66, label: '8 puan', note: 'Büyük sıçrama — FSRS olgunlaşıyor.' },
    { score: 69, label: '11 puan', note: '72\'ye 3 puan kaldı.' },
    { score: 72, label: 'Hedef', note: 'Tamamsın.' },
  ];

  // Her puan seviyesi için TUS sıralama verileri (ekran görüntüsünden)
  const SCORE_RANKS = [
    { score: 58, rank: 8500, pct: 21.2, label: 'Başlangıç' },
    { score: 59, rank: 7400, pct: 18.4, label: '+1 Puan' },
    { score: 60, rank: 6350, pct: 15.9, label: '+2 Puan' },
    { score: 61, rank: 5400, pct: 13.6, label: '+3 Puan' },
    { score: 62, rank: 4600, pct: 11.5, label: '+4 Puan' },
    { score: 63, rank: 3900, pct: 9.7,  label: 'Yarı Yolda' },
    { score: 64, rank: 3250, pct: 8.1,  label: '+6 Puan' },
    { score: 65, rank: 2700, pct: 6.7,  label: '+7 Puan' },
    { score: 66, rank: 2200, pct: 5.5,  label: '+8 Puan' },
    { score: 67, rank: 1800, pct: 4.5,  label: '+9 Puan' },
    { score: 68, rank: 1450, pct: 3.6,  label: '+10 Puan' },
    { score: 69, rank: 1150, pct: 2.9,  label: '+11 Puan' },
    { score: 70, rank: 900,  pct: 2.3,  label: '+12 Puan' },
    { score: 71, rank: 720,  pct: 1.8,  label: '+13 Puan' },
    { score: 72, rank: 560,  pct: 1.4,  label: 'HEDEF 🎯' },
  ];

  function scoreRankFor(score) {
    const floored = Math.floor(score);
    return SCORE_RANKS.find(r => r.score === floored) || SCORE_RANKS[0];
  }

  function nextMilestone(score) {
    return MILESTONES.find(m => m.score > score) || MILESTONES[MILESTONES.length - 1];
  }

  // Streak — arka arkaya her bloğu tamamlanan günler
  function currentStreak(days, todayStr) {
    let streak = 0;
    let cur = new Date(todayStr);
    cur.setDate(cur.getDate() - 1); // dünden geri
    while (true) {
      const ds = cur.toISOString().slice(0, 10);
      if (ds < PLAN_START_STR) break;
      const d = days[ds];
      if (!d) break;
      const all = [...(d.morning || []), ...(d.evening || [])];
      if (all.some(t => t.kind === 'off' || t.kind === 'exam' || t.kind === 'tus')) {
        cur.setDate(cur.getDate() - 1);
        continue;
      }
      const planned = Math.min(8, Math.max(4, Math.round(
        all.filter(t => !t.locked).reduce((a, t) => a + (t.hours || 0), 0)
      )));
      const doneBlocks = (d.hourBlocks || []).filter(Boolean).length;
      if (planned > 0 && doneBlocks >= planned) {
        streak++;
        cur.setDate(cur.getDate() - 1);
      } else {
        break;
      }
    }
    return streak;
  }

  return {
    PLAN_START_STR, PLAN_END_STR, TUS_STR,
    START_SCORE, TARGET_SCORE, DELTA_SCORE, TOTAL_HOURS,
    MONTH_BOUNDS, MILESTONES, SCORE_RANKS,
    planDayCount,
    monthFactorFor,
    computeTotalEffective,
    pointsPerHour,
    dayMaxPoints,
    dayEarnedPoints,
    dayMissedPoints,
    totalEarned,
    expectedByDate,
    missedByLesson,
    nextMilestone,
    scoreRankFor,
    currentStreak,
  };
})();

window.GAMIFY = GAMIFY;
