package spells

import (
	"fmt"

	"dk/internal/database"
)

// Spell represents a spell in the game
type Spell struct {
	ID    int
	Type  int
	Name  string
	Lore  string
	Icon  string
	MP    int
	Power int
}

// SpellType constants for spell types
const (
	TypeHeal        = 0
	TypeDamage      = 1
	TypeSleep       = 2
	TypeUberAttack  = 3
	TypeUberDefense = 4
)

// New creates a new Spell with sensible defaults
func New() *Spell {
	return &Spell{
		Type:  TypeHeal,
		Name:  "",
		Lore:  "",
		Icon:  "",
		MP:    5,
		Power: 10,
	}
}

// Validate checks if spell has valid values
func (s *Spell) Validate() error {
	if s.Name == "" {
		return fmt.Errorf("spell name cannot be empty")
	}
	if s.MP < 0 {
		return fmt.Errorf("spell MP cannot be negative")
	}
	if s.Power < 0 {
		return fmt.Errorf("spell Power cannot be negative")
	}
	if s.Type < TypeHeal || s.Type > TypeUberDefense {
		return fmt.Errorf("invalid spell type: %d", s.Type)
	}
	return nil
}

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

func (s *Spell) Insert() error {
	id, err := database.Insert("spells", s, "ID")
	if err != nil {
		return err
	}
	s.ID = int(id)
	return nil
}

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

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

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

func ByMaxMP(maxMP int) ([]*Spell, error) {
	var spells []*Spell
	err := database.Select(&spells, "SELECT * FROM spells WHERE mp <= %d ORDER BY type ASC, mp ASC, id ASC", maxMP)
	return spells, err
}

func ByTypeAndMaxMP(spellType, maxMP int) ([]*Spell, error) {
	var spells []*Spell
	err := database.Select(&spells, "SELECT * FROM spells WHERE type = %d AND mp <= %d ORDER BY mp ASC, id ASC", spellType, maxMP)
	return spells, err
}

func ByName(name string) (*Spell, error) {
	var spell Spell
	err := database.Get(&spell, "SELECT * FROM spells WHERE name = %s COLLATE NOCASE", name)
	if err != nil {
		return nil, fmt.Errorf("spell with name '%s' not found", name)
	}
	return &spell, nil
}

// Spell unlock functions
func UnlocksForClassAtLevel(classID, level int) ([]*Spell, error) {
	var spells []*Spell
	query := `
		SELECT s.* FROM spells s
		JOIN spell_unlocks u ON s.id = u.spell_id
		WHERE u.class_id = %d AND u.level = %d
		ORDER BY s.type ASC, s.mp ASC, s.id ASC`
	err := database.Select(&spells, query, classID, level)
	return spells, err
}

func UserSpells(userID int) ([]*Spell, error) {
	var spells []*Spell
	query := `
		SELECT s.* FROM spells s
		JOIN user_spells us ON s.id = us.spell_id
		WHERE us.user_id = %d
		ORDER BY s.type ASC, s.mp ASC, s.id ASC`
	err := database.Select(&spells, query, userID)
	return spells, err
}

func UserHealingSpells(userID int) ([]*Spell, error) {
	var spells []*Spell
	query := `
		SELECT s.* FROM spells s
		JOIN user_spells us ON s.id = us.spell_id
		WHERE us.user_id = %d AND s.type = 0
		ORDER BY s.mp ASC, s.id ASC`
	err := database.Select(&spells, query, userID)
	return spells, err
}

func GrantSpell(userID, spellID int) error {
	return database.Exec("INSERT OR IGNORE INTO user_spells (user_id, spell_id) VALUES (%d, %d)", userID, spellID)
}

func GrantSpells(userID int, spellIDs []int) error {
	return database.Transaction(func() error {
		for _, spellID := range spellIDs {
			if err := GrantSpell(userID, spellID); err != nil {
				return err
			}
		}
		return nil
	})
}

func HasSpell(userID, spellID int) bool {
	var count int
	err := database.Get(&count, "SELECT COUNT(*) FROM user_spells WHERE user_id = %d AND spell_id = %d", userID, spellID)
	return err == nil && count > 0
}

// Helper methods
func (s *Spell) IsHeal() bool {
	return s.Type == TypeHeal
}

func (s *Spell) IsDamage() bool {
	return s.Type == TypeDamage
}

func (s *Spell) IsSleep() bool {
	return s.Type == TypeSleep
}

func (s *Spell) IsUberAttack() bool {
	return s.Type == TypeUberAttack
}

func (s *Spell) IsUberDefense() bool {
	return s.Type == TypeUberDefense
}

func (s *Spell) TypeName() string {
	switch s.Type {
	case TypeHeal:
		return "Heal"
	case TypeDamage:
		return "Damage"
	case TypeSleep:
		return "Sleep"
	case TypeUberAttack:
		return "Uber Attack"
	case TypeUberDefense:
		return "Uber Defense"
	default:
		return "Unknown"
	}
}

func (s *Spell) CanCast(availableMP int) bool {
	return availableMP >= s.MP
}

func (s *Spell) Efficiency() float64 {
	if s.MP == 0 {
		return 0
	}
	return float64(s.Power) / float64(s.MP)
}

func (s *Spell) IsOffensive() bool {
	return s.Type == TypeDamage || s.Type == TypeSleep
}

func (s *Spell) IsSupport() bool {
	return s.Type == TypeHeal || s.Type == TypeUberAttack || s.Type == TypeUberDefense
}
