package spells

import (
	"fmt"
	"strings"

	nigiri "git.sharkk.net/Sharkk/Nigiri"
)

// Spell represents a spell in the game
type Spell struct {
	ID        int    `json:"id"`
	Name      string `json:"name" db:"required,unique"`
	MP        int    `json:"mp" db:"index"`
	Attribute int    `json:"attribute"`
	Type      int    `json:"type" db:"index"`
}

// SpellType constants for spell types
const (
	TypeHealing      = 1
	TypeHurt         = 2
	TypeSleep        = 3
	TypeAttackBoost  = 4
	TypeDefenseBoost = 5
)

// Global store
var store *nigiri.BaseStore[Spell]

// Init sets up the Nigiri store and indices
func Init(collection *nigiri.Collection) {
	store = nigiri.NewBaseStore[Spell]()

	// Register custom indices
	store.RegisterIndex("byType", nigiri.BuildIntGroupIndex(func(s *Spell) int {
		return s.Type
	}))

	store.RegisterIndex("byName", nigiri.BuildCaseInsensitiveLookupIndex(func(s *Spell) string {
		return s.Name
	}))

	store.RegisterIndex("byMP", nigiri.BuildIntGroupIndex(func(s *Spell) int {
		return s.MP
	}))

	store.RegisterIndex("allByTypeMP", nigiri.BuildSortedListIndex(func(a, b *Spell) bool {
		if a.Type != b.Type {
			return a.Type < b.Type
		}
		if a.MP != b.MP {
			return a.MP < b.MP
		}
		return a.ID < b.ID
	}))

	store.RebuildIndices()
}

// GetStore returns the spells store
func GetStore() *nigiri.BaseStore[Spell] {
	if store == nil {
		panic("spells store not initialized - call Initialize first")
	}
	return store
}

// Creates a new Spell with sensible defaults
func New() *Spell {
	return &Spell{
		Name:      "",
		MP:        5,           // Default MP cost
		Attribute: 10,          // Default attribute value
		Type:      TypeHealing, // Default to healing spell
	}
}

// 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.Attribute < 0 {
		return fmt.Errorf("spell Attribute cannot be negative")
	}
	if s.Type < TypeHealing || s.Type > TypeDefenseBoost {
		return fmt.Errorf("invalid spell type: %d", s.Type)
	}
	return nil
}

// CRUD operations
func (s *Spell) Save() error {
	if s.ID == 0 {
		id, err := store.Create(s)
		if err != nil {
			return err
		}
		s.ID = id
		return nil
	}
	return store.Update(s.ID, s)
}

func (s *Spell) Delete() error {
	store.Remove(s.ID)
	return nil
}

// Insert with ID assignment
func (s *Spell) Insert() error {
	id, err := store.Create(s)
	if err != nil {
		return err
	}
	s.ID = id
	return nil
}

// Query functions
func Find(id int) (*Spell, error) {
	spell, exists := store.Find(id)
	if !exists {
		return nil, fmt.Errorf("spell with ID %d not found", id)
	}
	return spell, nil
}

func All() ([]*Spell, error) {
	return store.AllSorted("allByTypeMP"), nil
}

func ByType(spellType int) ([]*Spell, error) {
	return store.GroupByIndex("byType", spellType), nil
}

func ByMaxMP(maxMP int) ([]*Spell, error) {
	return store.FilterByIndex("allByTypeMP", func(s *Spell) bool {
		return s.MP <= maxMP
	}), nil
}

func ByTypeAndMaxMP(spellType, maxMP int) ([]*Spell, error) {
	return store.FilterByIndex("allByTypeMP", func(s *Spell) bool {
		return s.Type == spellType && s.MP <= maxMP
	}), nil
}

func ByName(name string) (*Spell, error) {
	spell, exists := store.LookupByIndex("byName", strings.ToLower(name))
	if !exists {
		return nil, fmt.Errorf("spell with name '%s' not found", name)
	}
	return spell, nil
}

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

func (s *Spell) IsHurt() bool {
	return s.Type == TypeHurt
}

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

func (s *Spell) IsAttackBoost() bool {
	return s.Type == TypeAttackBoost
}

func (s *Spell) IsDefenseBoost() bool {
	return s.Type == TypeDefenseBoost
}

func (s *Spell) TypeName() string {
	switch s.Type {
	case TypeHealing:
		return "Healing"
	case TypeHurt:
		return "Hurt"
	case TypeSleep:
		return "Sleep"
	case TypeAttackBoost:
		return "Attack Boost"
	case TypeDefenseBoost:
		return "Defense Boost"
	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.Attribute) / float64(s.MP)
}

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

func (s *Spell) IsSupport() bool {
	return s.Type == TypeHealing || s.Type == TypeAttackBoost || s.Type == TypeDefenseBoost
}

// Legacy compatibility functions (will be removed later)
func LoadData(dataPath string) error {
	// No longer needed - Nigiri handles this
	return nil
}

func SaveData(dataPath string) error {
	// No longer needed - Nigiri handles this
	return nil
}
