package items

import (
	"fmt"

	"dk/internal/database"
)

// Item represents an item in the game
type Item struct {
	ID        int    `db:"id"`
	Type      int    `db:"type"`
	Name      string `db:"name"`
	Lore      string `db:"lore"`
	Value     int    `db:"value"`
	Attack    int    `db:"attack"`
	Defense   int    `db:"defense"`
	Strength  int    `db:"strength"`
	Dexterity int    `db:"dexterity"`
	MaxHP     int    `db:"max_hp"`
	MaxMP     int    `db:"max_mp"`
	ExpBonus  int    `db:"exp_bonus"`
	GoldBonus int    `db:"gold_bonus"`
	Special   string `db:"special"`
}

// ItemType constants for item types
const (
	TypeWeapon    = 1
	TypeArmor     = 2
	TypeShield    = 3
	TypeAccessory = 4
)

// New creates a new Item with sensible defaults
func New() *Item {
	return &Item{
		Type:      TypeWeapon,
		Name:      "",
		Lore:      "",
		Value:     0,
		Attack:    0,
		Defense:   0,
		Strength:  0,
		Dexterity: 0,
		MaxHP:     0,
		MaxMP:     0,
		ExpBonus:  0,
		GoldBonus: 0,
		Special:   "",
	}
}

// Validate checks if item has valid values
func (i *Item) Validate() error {
	if i.Name == "" {
		return fmt.Errorf("item name cannot be empty")
	}
	if i.Type < TypeWeapon || i.Type > TypeAccessory {
		return fmt.Errorf("invalid item type: %d", i.Type)
	}
	if i.Value < 0 {
		return fmt.Errorf("item value cannot be negative")
	}
	return nil
}

// CRUD operations
func (i *Item) Delete() error {
	return database.Exec("DELETE FROM items WHERE id = %d", i.ID)
}

func (i *Item) Insert() error {
	id, err := database.Insert("items", i, "id")
	if err != nil {
		return err
	}
	i.ID = int(id)
	return nil
}

func (i *Item) Update() error {
	fields := map[string]any{
		"type":       i.Type,
		"name":       i.Name,
		"lore":       i.Lore,
		"value":      i.Value,
		"attack":     i.Attack,
		"defense":    i.Defense,
		"strength":   i.Strength,
		"dexterity":  i.Dexterity,
		"max_hp":     i.MaxHP,
		"max_mp":     i.MaxMP,
		"exp_bonus":  i.ExpBonus,
		"gold_bonus": i.GoldBonus,
		"special":    i.Special,
	}
	return database.Update("items", fields, "id", i.ID)
}

// Query functions
func Find(id int) (*Item, error) {
	var item Item
	err := database.Get(&item, "SELECT * FROM items WHERE id = %d", id)
	if err != nil {
		return nil, fmt.Errorf("item with ID %d not found", id)
	}
	return &item, nil
}

func All() ([]*Item, error) {
	var items []*Item
	err := database.Select(&items, "SELECT * FROM items ORDER BY type ASC, value ASC, id ASC")
	return items, err
}

func ByType(itemType int) ([]*Item, error) {
	var items []*Item
	err := database.Select(&items, "SELECT * FROM items WHERE type = %d ORDER BY value ASC, id ASC", itemType)
	return items, err
}

func ByValueRange(minValue, maxValue int) ([]*Item, error) {
	var items []*Item
	err := database.Select(&items, "SELECT * FROM items WHERE value >= %d AND value <= %d ORDER BY value ASC, id ASC", minValue, maxValue)
	return items, err
}

// Helper methods
func (i *Item) IsWeapon() bool {
	return i.Type == TypeWeapon
}

func (i *Item) IsArmor() bool {
	return i.Type == TypeArmor
}

func (i *Item) IsShield() bool {
	return i.Type == TypeShield
}

func (i *Item) IsAccessory() bool {
	return i.Type == TypeAccessory
}

func (i *Item) TypeName() string {
	switch i.Type {
	case TypeWeapon:
		return "Weapon"
	case TypeArmor:
		return "Armor"
	case TypeShield:
		return "Shield"
	case TypeAccessory:
		return "Accessory"
	default:
		return "Unknown"
	}
}

func (i *Item) HasSpecial() bool {
	return i.Special != ""
}

func (i *Item) IsEquippable() bool {
	return i.Type >= TypeWeapon && i.Type <= TypeShield
}

func (i *Item) IsSlottable() bool {
	return i.Type == TypeAccessory
}

func (i *Item) HasLore() bool {
	return i.Lore != ""
}

// Stat bonus methods
func (i *Item) HasAttackBonus() bool {
	return i.Attack != 0
}

func (i *Item) HasDefenseBonus() bool {
	return i.Defense != 0
}

func (i *Item) HasStrengthBonus() bool {
	return i.Strength != 0
}

func (i *Item) HasDexterityBonus() bool {
	return i.Dexterity != 0
}

func (i *Item) HasHPBonus() bool {
	return i.MaxHP != 0
}

func (i *Item) HasMPBonus() bool {
	return i.MaxMP != 0
}

func (i *Item) HasExpBonus() bool {
	return i.ExpBonus != 0
}

func (i *Item) HasGoldBonus() bool {
	return i.GoldBonus != 0
}

// Returns true if the item provides any stat bonuses
func (i *Item) HasStatBonuses() bool {
	return i.Attack != 0 || i.Defense != 0 || i.Strength != 0 ||
		i.Dexterity != 0 || i.MaxHP != 0 || i.MaxMP != 0 ||
		i.ExpBonus != 0 || i.GoldBonus != 0
}

func (i *Item) GetStatBonuses() map[string]int {
	bonuses := make(map[string]int)

	if i.Attack != 0 {
		bonuses["Attack"] = i.Attack
	}
	if i.Defense != 0 {
		bonuses["Defense"] = i.Defense
	}
	if i.Strength != 0 {
		bonuses["Strength"] = i.Strength
	}
	if i.Dexterity != 0 {
		bonuses["Dexterity"] = i.Dexterity
	}
	if i.MaxHP != 0 {
		bonuses["Max HP"] = i.MaxHP
	}
	if i.MaxMP != 0 {
		bonuses["Max MP"] = i.MaxMP
	}
	if i.ExpBonus != 0 {
		bonuses["Exp Bonus"] = i.ExpBonus
	}
	if i.GoldBonus != 0 {
		bonuses["Gold Bonus"] = i.GoldBonus
	}

	return bonuses
}

// GetPrimaryStatBonus returns the main stat bonus for the item type
func (i *Item) GetPrimaryStatBonus() int {
	switch i.Type {
	case TypeWeapon:
		return i.Attack
	case TypeArmor, TypeShield:
		return i.Defense
	case TypeAccessory:
		// For accessories, return the highest stat bonus
		max := 0
		stats := []int{i.Attack, i.Defense, i.Strength, i.Dexterity, i.MaxHP, i.MaxMP}
		for _, stat := range stats {
			if abs(stat) > abs(max) {
				max = stat
			}
		}
		return max
	default:
		return 0
	}
}

func abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}
