// genenemies prints SQL INSERT statements for public.enemies (220 rows: 22 archetypes × 5 level sub-bands × 2 biomes).
// Biome ids match internal/world.Service levelBands (meadow, forest, ruins, canyon, swamp, volcanic, astral).
// Each archetype uses min/max level span from CSV/spec (see arcLevelRange); span is split into 5 contiguous bands.
// Run from backend: go run ./cmd/genenemies > migrations/000006b_enemy_data.sql
package main

import (
	"fmt"
	"strings"
)

type anchor struct {
	hp, atk, def     int
	speed            float64
	crit             float64
	isElite          bool
	hpPL, atkPL, defPL float64
	xpRew, goldRew   int64
	abilities        []string
}

// Thirteen CSV rows (000003/000005) drive mechanics; twelve user archetypes map 1:1 except element uses water+ice.
var csvAnchors = map[string]anchor{
	"wolf":            {hp: 94, atk: 20, def: 1, speed: 1.8, crit: 0.05, hpPL: 7.8681, atkPL: 2.7054, defPL: 1.2, xpRew: 1, goldRew: 1, abilities: nil},
	"boar":            {hp: 102, atk: 25, def: 2, speed: 0.8, crit: 0.08, hpPL: 8.2826, atkPL: 2.319, defPL: 1.6, xpRew: 2, goldRew: 1, abilities: nil},
	"zombie":          {hp: 107, atk: 28, def: 2, speed: 0.5, crit: 0, hpPL: 6.9412, atkPL: 2.5898, defPL: 1.8, xpRew: 5, goldRew: 1, abilities: []string{"poison"}},
	"spider":          {hp: 118, atk: 24, def: 1, speed: 2.0, crit: 0.15, hpPL: 12.0614, atkPL: 2.7373, defPL: 1.0, xpRew: 7, goldRew: 1, abilities: []string{"critical"}},
	"orc":             {hp: 113, atk: 27, def: 3, speed: 1.0, crit: 0.05, hpPL: 7.1338, atkPL: 2.6581, defPL: 2.0, xpRew: 8, goldRew: 1, abilities: []string{"burst"}},
	"skeleton":        {hp: 132, atk: 28, def: 2, speed: 1.3, crit: 0.06, hpPL: 8.5586, atkPL: 2.2939, defPL: 1.7, xpRew: 9, goldRew: 1, abilities: []string{"dodge"}}, // skeleton_archer CSV
	"battle_lizard":   {hp: 105, atk: 32, def: 4, speed: 0.7, crit: 0.03, hpPL: 5.7476, atkPL: 2.414, defPL: 2.3, xpRew: 10, goldRew: 1, abilities: []string{"regen"}},
	"element_water":   {hp: 349, atk: 45, def: 5, speed: 0.8, crit: 0.05, hpPL: 8.0285, atkPL: 3.1288, defPL: 2.2, xpRew: 36, goldRew: 1, isElite: true, abilities: []string{"slow"}},
	"element_ice":     {hp: 208, atk: 37, def: 6, speed: 0.7, crit: 0.04, hpPL: 7.5649, atkPL: 3.0394, defPL: 2.5, xpRew: 18, goldRew: 1, isElite: true, abilities: []string{"ice_slow"}},
	"demon":           {hp: 177, atk: 25, def: 3, speed: 1.2, crit: 0.1, hpPL: 11.72, atkPL: 2.6587, defPL: 2.0, xpRew: 11, goldRew: 1, isElite: true, abilities: []string{"burn"}},
	"skeleton_king":   {hp: 149, atk: 24, def: 22, speed: 0.9, crit: 0.08, hpPL: 4.1663, atkPL: 1.8339, defPL: 2.0, xpRew: 35, goldRew: 1, isElite: true, abilities: []string{"regen", "summon"}},
	"forest_warden":   {hp: 338, atk: 50, def: 8, speed: 0.5, crit: 0.03, hpPL: 6.1288, atkPL: 3.5033, defPL: 2.8, xpRew: 37, goldRew: 1, isElite: true, abilities: []string{"regen"}},
	"titan":           {hp: 583, atk: 48, def: 6, speed: 1.5, crit: 0.12, hpPL: 11.1055, atkPL: 2.9104, defPL: 2.3, xpRew: 38, goldRew: 10, isElite: true, abilities: []string{"stun", "chain_lightning"}},
	// ten new — synthetic
	"golem":           {hp: 220, atk: 35, def: 10, speed: 0.55, crit: 0.02, hpPL: 8.0, atkPL: 2.8, defPL: 3.0, xpRew: 15, goldRew: 2, abilities: []string{"stun"}},
	"wraith":          {hp: 100, atk: 30, def: 1, speed: 1.1, crit: 0.06, hpPL: 6.5, atkPL: 2.7, defPL: 1.0, xpRew: 12, goldRew: 1, abilities: []string{"dodge"}},
	"bandit":          {hp: 110, atk: 26, def: 2, speed: 1.15, crit: 0.07, hpPL: 7.2, atkPL: 2.5, defPL: 1.5, xpRew: 9, goldRew: 2, abilities: []string{"burst"}},
	"cultist":         {hp: 95, atk: 22, def: 2, speed: 0.9, crit: 0.05, hpPL: 5.5, atkPL: 2.4, defPL: 1.4, xpRew: 10, goldRew: 1, abilities: []string{"burn"}},
	"treant":          {hp: 300, atk: 40, def: 9, speed: 0.45, crit: 0.02, hpPL: 7.0, atkPL: 3.2, defPL: 2.9, xpRew: 32, goldRew: 1, isElite: true, abilities: []string{"regen"}},
	"basilisk":        {hp: 125, atk: 26, def: 3, speed: 1.0, crit: 0.12, hpPL: 9.0, atkPL: 2.6, defPL: 1.8, xpRew: 14, goldRew: 1, abilities: []string{"poison", "critical"}},
	"wyvern":          {hp: 160, atk: 30, def: 4, speed: 1.4, crit: 0.09, hpPL: 8.5, atkPL: 2.7, defPL: 2.0, xpRew: 16, goldRew: 2, abilities: []string{"burn"}},
	"harpy":           {hp: 115, atk: 27, def: 2, speed: 1.6, crit: 0.11, hpPL: 7.8, atkPL: 2.5, defPL: 1.2, xpRew: 11, goldRew: 1, abilities: []string{"critical"}},
	"manticore":       {hp: 190, atk: 33, def: 5, speed: 0.85, crit: 0.08, hpPL: 9.2, atkPL: 2.8, defPL: 2.1, xpRew: 19, goldRew: 2, abilities: []string{"poison", "burst"}},
	"shade":           {hp: 130, atk: 28, def: 2, speed: 1.0, crit: 0.05, hpPL: 6.8, atkPL: 2.6, defPL: 1.3, xpRew: 17, goldRew: 1, abilities: []string{"slow", "dodge"}},
}

// Archetype order: 22 entries — keys match DB archetype column.
var archetypeOrder = []string{
	"wolf", "boar", "zombie", "spider", "orc", "skeleton", "battle_lizard",
	"element", "demon", "skeleton_king", "forest_warden", "titan",
	"golem", "wraith", "bandit", "cultist", "treant", "basilisk", "wyvern", "harpy", "manticore", "shade",
}

func anchorForArchetype(arch string, biomeIdx int) anchor {
	switch arch {
	case "element":
		if biomeIdx == 0 {
			return csvAnchors["element_water"]
		}
		return csvAnchors["element_ice"]
	default:
		return csvAnchors[arch]
	}
}

// arcLevelRange: inclusive [min,max] per archetype from specification / CSV anchors (13 types + 10 synthetic).
var arcLevelRange = map[string][2]int{
	"wolf":          {1, 5},
	"boar":          {2, 6},
	"zombie":        {3, 8},
	"spider":        {4, 9},
	"orc":           {5, 12},
	"skeleton":      {6, 14},
	"battle_lizard": {7, 15},
	"demon":         {10, 20},
	"skeleton_king": {15, 25},
	"forest_warden": {20, 30},
	"titan":         {25, 35},
	// element: water vs ice ranges (per biome index in generator)
	"golem":     {8, 18},
	"wraith":    {5, 14},
	"bandit":    {4, 12},
	"cultist":   {6, 16},
	"treant":    {18, 30},
	"basilisk":  {9, 19},
	"wyvern":    {12, 24},
	"harpy":     {6, 15},
	"manticore": {14, 26},
	"shade":     {10, 22},
}

// elementWaterRange / elementIceRange match CSV water_element vs ice_guardian bands.
var elementWaterRange = [2]int{18, 28}
var elementIceRange = [2]int{12, 22}

func levelRangeFor(arch string, biomeIdx int) (int, int) {
	if arch == "element" {
		if biomeIdx == 0 {
			return elementWaterRange[0], elementWaterRange[1]
		}
		return elementIceRange[0], elementIceRange[1]
	}
	r, ok := arcLevelRange[arch]
	if !ok {
		return 1, 10
	}
	return r[0], r[1]
}

// splitRange divides [minL,maxL] into `parts` contiguous inclusive bands.
func splitRange(minL, maxL, parts int) [][2]int {
	if parts <= 0 {
		return nil
	}
	if minL > maxL {
		minL, maxL = maxL, minL
	}
	span := maxL - minL + 1
	out := make([][2]int, parts)
	if span <= 0 {
		for i := range out {
			out[i] = [2]int{minL, maxL}
		}
		return out
	}
	if span < parts {
		for i := 0; i < parts; i++ {
			if i < span {
				lv := minL + i
				if lv > maxL {
					lv = maxL
				}
				out[i] = [2]int{lv, lv}
			} else {
				out[i] = [2]int{maxL, maxL}
			}
		}
		return out
	}
	step := span / parts
	rem := span % parts
	cur := minL
	for i := 0; i < parts; i++ {
		sz := step
		if i < rem {
			sz++
		}
		lo := cur
		hi := cur + sz - 1
		cur = hi + 1
		out[i] = [2]int{lo, hi}
	}
	return out
}

func scaleForMidpoint(mid int) float64 {
	// Roughly matches old 5-band progression (~1.0 … ~2.35 for mid 1..45).
	s := 1.0 + float64(mid-1)*0.031
	if s < 0.85 {
		s = 0.85
	}
	if s > 2.6 {
		s = 2.6
	}
	return s
}

var biomePairs = [][2]string{
	{"meadow", "forest"},
	{"forest", "ruins"},
	{"ruins", "canyon"},
	{"canyon", "swamp"},
	{"volcanic", "astral"},
}

func main() {
	id := 1
	for _, arch := range archetypeOrder {
		for bandIdx := 0; bandIdx < 5; bandIdx++ {
			pair := biomePairs[bandIdx]
			for j, biome := range pair {
				a := anchorForArchetype(arch, j)
				lo, hi := levelRangeFor(arch, j)
				bands := splitRange(lo, hi, 5)
				br := bands[bandIdx]
				minL, maxL := br[0], br[1]
				baseLv := (minL + maxL) / 2
				if baseLv < 1 {
					baseLv = 1
				}
				mid := (minL + maxL) / 2
				scale := scaleForMidpoint(mid)
				mult := scale
				if j == 0 {
					mult *= 0.95
				} else {
					mult *= 1.05
				}
				slug := fmt.Sprintf("%s_l%d_%d_%s", arch, minL, maxL, biome)
				name := makeName(arch, biome, bandIdx, j)
				hp := int(float64(a.hp) * mult)
				if hp < 1 {
					hp = 1
				}
				atk := int(float64(a.atk) * mult)
				if atk < 1 {
					atk = 1
				}
				def := int(float64(a.def) * mult)
				if a.def > 0 && def < 1 {
					def = 1
				}
				speed := a.speed * (0.97 + float64(bandIdx)*0.01)
				if speed < 0.1 {
					speed = 0.1
				}
				crit := a.crit
				hpPL := a.hpPL * (1 + float64(bandIdx)*0.08)
				atkPL := a.atkPL * (1 + float64(bandIdx)*0.06)
				defPL := a.defPL * (1 + float64(bandIdx)*0.05)
				xpRew := a.xpRew + int64(bandIdx*3+j)
				if xpRew < 1 {
					xpRew = 1
				}
				goldRew := a.goldRew
				if a.isElite && bandIdx >= 3 {
					goldRew += int64(bandIdx - 2)
				}
				abilities := formatAbilities(variantAbilities(a.abilities, bandIdx, j))
				elite := a.isElite
				fmt.Printf(`INSERT INTO public.enemies (id, type, archetype, biome, name, hp, max_hp, attack, defense, speed, crit_chance, min_level, max_level, xp_reward, gold_reward, special_abilities, is_elite, created_at, base_level, level_variance_pct, max_hero_level_diff, hp_per_level, attack_per_level, defense_per_level, xp_per_level, gold_per_level) VALUES (%d, %s, %s, %s, %s, %d, %d, %d, %d, %.4f, %.4f, %d, %d, %d, %d, %s, %t, now(), %d, 0.3, 5, %.4f, %.4f, %.4f, 2.0, 1.2);
`,
					id, quote(slug), quote(arch), quote(biome), quote(name), hp, hp, atk, def, speed, crit,
					minL, maxL, xpRew, goldRew, abilities, elite, baseLv,
					hpPL, atkPL, defPL,
				)
				id++
			}
		}
	}
}

func quote(s string) string {
	return "'" + strings.ReplaceAll(s, "'", "''") + "'"
}

func formatAbilities(a []string) string {
	if len(a) == 0 {
		return "ARRAY[]::text[]"
	}
	var b strings.Builder
	b.WriteString("ARRAY[")
	for i, x := range a {
		if i > 0 {
			b.WriteString(",")
		}
		b.WriteString("'")
		b.WriteString(strings.ReplaceAll(x, "'", "''"))
		b.WriteString("'")
	}
	b.WriteString("]::text[]")
	return b.String()
}

func variantAbilities(base []string, bandIdx, biomeIdx int) []string {
	if len(base) == 0 {
		return nil
	}
	out := append([]string(nil), base...)
	if bandIdx%2 == 0 && biomeIdx == 0 && len(out) > 1 {
		out = out[:len(out)-1]
	}
	return out
}

func makeName(arch, biome string, bandIdx, biomeIdx int) string {
	prefix := []string{"Elder", "Young", "Lost", "Cursed", "Rogue", "Ancient", "Feral", "Twilight", "Ashen", "Deep"}[bandIdx%10]
	biomeAdj := map[string]string{
		"meadow": "Verdant", "forest": "Woodland", "ruins": "Forgotten", "canyon": "Rift",
		"swamp": "Bog", "volcanic": "Ember", "astral": "Astral",
	}
	adj := biomeAdj[biome]
	if adj == "" {
		adj = biome
	}
	species := map[string]string{
		"wolf": "Wolf", "boar": "Boar", "zombie": "Zombie", "spider": "Spider", "orc": "Orc",
		"skeleton": "Skeleton", "battle_lizard": "Scaleback", "element": "Elemental",
		"demon": "Demon", "skeleton_king": "Bone Sovereign", "forest_warden": "Warden", "titan": "Titan",
		"golem": "Golem", "wraith": "Wraith", "bandit": "Bandit", "cultist": "Cultist", "treant": "Treant",
		"basilisk": "Basilisk", "wyvern": "Wyvern", "harpy": "Harpy", "manticore": "Manticore", "shade": "Shade",
	}
	sp := species[arch]
	if biomeIdx == 1 {
		return fmt.Sprintf("%s %s %s", adj, prefix, sp)
	}
	return fmt.Sprintf("%s %s %s", prefix, adj, sp)
}
