package storage

import (
	"context"
	"fmt"
	"strings"

	"github.com/jackc/pgx/v5/pgxpool"

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

type ContentStore struct {
	pool *pgxpool.Pool
}

func NewContentStore(pool *pgxpool.Pool) *ContentStore {
	return &ContentStore{pool: pool}
}

func (s *ContentStore) LoadEnemyTemplates(ctx context.Context) (map[model.EnemyType]model.Enemy, error) {
	rows, err := s.pool.Query(ctx, `
		SELECT type, name, hp, max_hp, attack, defense, speed, crit_chance,
		       min_level, max_level, xp_reward, gold_reward, special_abilities, is_elite
		FROM enemies
	`)
	if err != nil {
		return nil, fmt.Errorf("load enemies from db: %w", err)
	}
	defer rows.Close()

	out := make(map[model.EnemyType]model.Enemy)
	for rows.Next() {
		var (
			t                 string
			e                 model.Enemy
			specialAbilities  []string
		)
		if err := rows.Scan(
			&t, &e.Name, &e.HP, &e.MaxHP, &e.Attack, &e.Defense, &e.Speed, &e.CritChance,
			&e.MinLevel, &e.MaxLevel, &e.XPReward, &e.GoldReward, &specialAbilities, &e.IsElite,
		); err != nil {
			return nil, fmt.Errorf("scan enemy row: %w", err)
		}
		e.Type = model.EnemyType(t)
		e.SpecialAbilities = make([]model.SpecialAbility, 0, len(specialAbilities))
		for _, a := range specialAbilities {
			e.SpecialAbilities = append(e.SpecialAbilities, model.SpecialAbility(a))
		}
		out[e.Type] = e
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("enemy rows: %w", err)
	}
	return out, nil
}

func normalizeEquipmentSlot(raw string) model.EquipmentSlot {
	v := strings.TrimSpace(strings.ToLower(raw))
	v = strings.TrimPrefix(v, "gear.slot.")
	switch v {
	case "weapon", "mainhand", "main_hand":
		return model.SlotMainHand
	case "armor", "chest":
		return model.SlotChest
	case "head":
		return model.SlotHead
	case "feet":
		return model.SlotFeet
	case "neck":
		return model.SlotNeck
	case "hands":
		return model.SlotHands
	case "legs":
		return model.SlotLegs
	case "cloak":
		return model.SlotCloak
	case "finger", "ring":
		return model.SlotFinger
	case "wrist":
		return model.SlotWrist
	default:
		return model.EquipmentSlot(v)
	}
}

func (s *ContentStore) LoadGearFamilies(ctx context.Context) ([]model.GearFamily, error) {
	out := make([]model.GearFamily, 0, 128)

	weaponRows, err := s.pool.Query(ctx, `
		SELECT name, type, damage, speed, crit_chance, special_effect
		FROM weapons
	`)
	if err != nil {
		return nil, fmt.Errorf("load weapons from db: %w", err)
	}
	for weaponRows.Next() {
		var name, typ, special string
		var damage int
		var speed, crit float64
		if err := weaponRows.Scan(&name, &typ, &damage, &speed, &crit, &special); err != nil {
			weaponRows.Close()
			return nil, fmt.Errorf("scan weapon row: %w", err)
		}
		out = append(out, model.GearFamily{
			Slot:          model.SlotMainHand,
			FormID:        "gear.form.main_hand." + typ,
			Name:          name,
			Subtype:       typ,
			BasePrimary:   damage,
			StatType:      "attack",
			SpeedModifier: speed,
			BaseCrit:      crit,
			SpecialEffect: special,
		})
	}
	weaponRows.Close()

	armorRows, err := s.pool.Query(ctx, `
		SELECT name, type, defense, speed_modifier, agility_bonus, set_name, special_effect
		FROM armor
	`)
	if err != nil {
		return nil, fmt.Errorf("load armor from db: %w", err)
	}
	for armorRows.Next() {
		var name, typ, setName, special string
		var defense, agi int
		var speed float64
		if err := armorRows.Scan(&name, &typ, &defense, &speed, &agi, &setName, &special); err != nil {
			armorRows.Close()
			return nil, fmt.Errorf("scan armor row: %w", err)
		}
		out = append(out, model.GearFamily{
			Slot:          model.SlotChest,
			FormID:        "gear.form.chest." + typ,
			Name:          name,
			Subtype:       typ,
			BasePrimary:   defense,
			StatType:      "defense",
			SpeedModifier: speed,
			AgilityBonus:  agi,
			SetName:       setName,
			SpecialEffect: special,
		})
	}
	armorRows.Close()

	eqRows, err := s.pool.Query(ctx, `
		SELECT slot, form_id, name, base_primary, stat_type
		FROM equipment_items
	`)
	if err != nil {
		return nil, fmt.Errorf("load equipment_items from db: %w", err)
	}
	for eqRows.Next() {
		var slot, formID, name, statType string
		var basePrimary int
		if err := eqRows.Scan(&slot, &formID, &name, &basePrimary, &statType); err != nil {
			eqRows.Close()
			return nil, fmt.Errorf("scan equipment_item row: %w", err)
		}
		out = append(out, model.GearFamily{
			Slot:          normalizeEquipmentSlot(slot),
			FormID:        formID,
			Name:          name,
			BasePrimary:   basePrimary,
			StatType:      statType,
			SpeedModifier: 1.0,
		})
	}
	eqRows.Close()

	return out, nil
}

