package main

import (
	"fmt"

	"github.com/denisovdennis/autohero/internal/game"
	"github.com/denisovdennis/autohero/internal/model"
)

// gearCheckScenariosForTemplate builds one fair-tier cell per level in the intersection of
// [t.MinLevel..t.MaxLevel] with [levelMin..levelMax] when those flags are > 0 (0 = no bound from that side).
func gearCheckScenariosForTemplate(t model.Enemy, levelMin, levelMax int) []gridScenario {
	minL := t.MinLevel
	maxL := t.MaxLevel
	if minL <= 0 || maxL < minL {
		lvl := (t.MinLevel + t.MaxLevel) / 2
		if lvl < 1 {
			lvl = 1
		}
		if t.BaseLevel > 0 {
			lvl = t.BaseLevel
		}
		if levelMin > 0 && lvl < levelMin {
			lvl = levelMin
		}
		if levelMax > 0 && lvl > levelMax {
			lvl = levelMax
		}
		if levelMin > 0 && levelMax > 0 && (lvl < levelMin || lvl > levelMax) {
			return nil
		}
		return []gridScenario{{heroLv: lvl, enemyLv: lvl, gearIdx: 0}}
	}
	if levelMin > 0 && levelMin > minL {
		minL = levelMin
	}
	if levelMax > 0 && levelMax < maxL {
		maxL = levelMax
	}
	if minL > maxL {
		return nil
	}
	out := make([]gridScenario, 0, maxL-minL+1)
	for lv := minL; lv <= maxL; lv++ {
		out = append(out, gridScenario{heroLv: lv, enemyLv: lv, gearIdx: 0})
	}
	return out
}

// runGearCheck compares baseline (common) vs max (legendary) reference gear at each level.
// Rules (best gear vs baseline):
//   - Kill time must not improve by more than maxSpeedupPct (median win duration max >= baseline * (1 - maxSpeedupPct/100)).
//   - Median hero HP%% on wins with best gear must be <= maxHeroHpPct/100.
func runGearCheck(
	tmpl model.Enemy,
	et string,
	scenarios []gridScenario,
	n int,
	seedBase int64,
	maxSpeedupPct float64,
	maxHeroHpPct float64,
	strict bool,
) (failCells int, lines []string) {
	minDurRatio := 1.0 - maxSpeedupPct/100.0
	maxHpFrac := maxHeroHpPct / 100.0
	if minDurRatio < 0 || minDurRatio > 1 {
		minDurRatio = 0.80
	}

	for _, sc := range scenarios {
		h := hashGridScenario(et, sc)
		heroB := game.NewReferenceHeroForBalance(sc.heroLv, game.ReferenceGearBaseline, nil)
		heroM := game.NewReferenceHeroForBalance(sc.heroLv, game.ReferenceGearMax, nil)

		rB := runOneGridScenario(tmpl, heroB, sc.enemyLv, n, seedBase, h)
		rM := runOneGridScenario(tmpl, heroM, sc.enemyLv, n, seedBase, h+0x100000)

		if rB.medianWinSec <= 0 {
			if strict {
				failCells++
				lines = append(lines, fmt.Sprintf(
					"FAIL %s L%d: baseline had no median win duration (strict; winRate=%.1f%%)",
					et, sc.heroLv, 100*rB.winRate))
			} else {
				lines = append(lines, fmt.Sprintf("# %s L%d: SKIP — baseline had no median win duration (winRate=%.1f%%)", et, sc.heroLv, 100*rB.winRate))
			}
			continue
		}
		if rM.medianWinSec <= 0 {
			failCells++
			lines = append(lines, fmt.Sprintf("FAIL %s L%d: max gear had no median win duration (winRate=%.1f%%)", et, sc.heroLv, 100*rM.winRate))
			continue
		}
		// Faster kill = lower duration. Allow at most maxSpeedupPct faster => durM >= durB * minDurRatio.
		failDur := rM.medianWinSec < rB.medianWinSec*minDurRatio-1e-6
		failHp := rM.medianHeroHp > maxHpFrac+1e-9
		if failDur || failHp {
			failCells++
			speedupPct := (1.0 - rM.medianWinSec/rB.medianWinSec) * 100.0
			lines = append(lines, fmt.Sprintf(
				"FAIL %s L%d: baseline dur=%.1fs hp=%.1f%% | max dur=%.1fs (~%.1f%% faster) need dur>=%.1fs | max hp=%.1f%% need <=%.1f%% | dur_ok=%v hp_ok=%v",
				et, sc.heroLv,
				rB.medianWinSec, 100*rB.medianHeroHp,
				rM.medianWinSec, speedupPct,
				rB.medianWinSec*minDurRatio,
				100*rM.medianHeroHp, maxHeroHpPct,
				!failDur, !failHp,
			))
		}
	}
	return failCells, lines
}
