package fightlogs

import (
	"fmt"
	"strings"
	"time"

	"dk/internal/database"
)

// FightLog represents a single action in a fight
type FightLog struct {
	ID      int
	FightID int
	Type    int
	Data    int
	Name    string
	Created int64
}

// Action type constants
const (
	ActionAttackHit     = 1
	ActionAttackMiss    = 2
	ActionSpellHeal     = 3
	ActionSpellHurt     = 4
	ActionRunSuccess    = 5
	ActionRunFail       = 6
	ActionGeneric       = 7
	ActionMonsterAttack = 8
	ActionMonsterMiss   = 9
	ActionMonsterSpell  = 10
	ActionMonsterDeath  = 11
)

// New creates a new FightLog with sensible defaults
func New(fightID int) *FightLog {
	return &FightLog{
		FightID: fightID,
		Type:    ActionGeneric,
		Data:    0,
		Name:    "",
		Created: time.Now().Unix(),
	}
}

// Validate checks if fight log has valid values
func (fl *FightLog) Validate() error {
	if fl.FightID <= 0 {
		return fmt.Errorf("fight log FightID must be positive")
	}
	if fl.Created <= 0 {
		return fmt.Errorf("fight log Created timestamp must be positive")
	}
	return nil
}

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

func (fl *FightLog) Insert() error {
	id, err := database.Insert("fight_logs", fl, "ID")
	if err != nil {
		return err
	}
	fl.ID = int(id)
	return nil
}

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

func ByFightID(fightID int) ([]*FightLog, error) {
	var logs []*FightLog
	err := database.Select(&logs, "SELECT * FROM fight_logs WHERE fight_id = %d ORDER BY created ASC, id ASC", fightID)
	return logs, err
}

func DeleteByFightID(fightID int) error {
	return database.Exec("DELETE FROM fight_logs WHERE fight_id = %d", fightID)
}

// Helper functions for adding different types of actions
func AddAction(fightID int, action string) error {
	log := &FightLog{
		FightID: fightID,
		Type:    ActionGeneric,
		Name:    action,
		Created: time.Now().Unix(),
	}
	return log.Insert()
}

func AddAttackHit(fightID, damage int) error {
	log := &FightLog{
		FightID: fightID,
		Type:    ActionAttackHit,
		Data:    damage,
		Created: time.Now().Unix(),
	}
	return log.Insert()
}

func AddAttackMiss(fightID int) error {
	log := &FightLog{
		FightID: fightID,
		Type:    ActionAttackMiss,
		Created: time.Now().Unix(),
	}
	return log.Insert()
}

func AddSpellHeal(fightID int, spellName string, healAmount int) error {
	log := &FightLog{
		FightID: fightID,
		Type:    ActionSpellHeal,
		Data:    healAmount,
		Name:    spellName,
		Created: time.Now().Unix(),
	}
	return log.Insert()
}

func AddSpellHurt(fightID int, spellName string, damage int) error {
	log := &FightLog{
		FightID: fightID,
		Type:    ActionSpellHurt,
		Data:    damage,
		Name:    spellName,
		Created: time.Now().Unix(),
	}
	return log.Insert()
}

func AddRunSuccess(fightID int) error {
	log := &FightLog{
		FightID: fightID,
		Type:    ActionRunSuccess,
		Created: time.Now().Unix(),
	}
	return log.Insert()
}

func AddRunFail(fightID int) error {
	log := &FightLog{
		FightID: fightID,
		Type:    ActionRunFail,
		Created: time.Now().Unix(),
	}
	return log.Insert()
}

func AddMonsterAttack(fightID int, monsterName string, damage int) error {
	log := &FightLog{
		FightID: fightID,
		Type:    ActionMonsterAttack,
		Data:    damage,
		Name:    monsterName,
		Created: time.Now().Unix(),
	}
	return log.Insert()
}

func AddMonsterMiss(fightID int, monsterName string) error {
	log := &FightLog{
		FightID: fightID,
		Type:    ActionMonsterMiss,
		Name:    monsterName,
		Created: time.Now().Unix(),
	}
	return log.Insert()
}

func AddMonsterSpell(fightID int, monsterName, spellName string, damage int) error {
	log := &FightLog{
		FightID: fightID,
		Type:    ActionMonsterSpell,
		Data:    damage,
		Name:    monsterName + "|" + spellName,
		Created: time.Now().Unix(),
	}
	return log.Insert()
}

func AddMonsterDeath(fightID int, monsterName string) error {
	log := &FightLog{
		FightID: fightID,
		Type:    ActionMonsterDeath,
		Name:    monsterName,
		Created: time.Now().Unix(),
	}
	return log.Insert()
}

// Convert logs to human-readable strings
func GetActions(fightID int) ([]string, error) {
	logs, err := ByFightID(fightID)
	if err != nil {
		return nil, err
	}

	result := make([]string, len(logs))
	for i, log := range logs {
		result[i] = log.ToString()
	}
	return result, nil
}

func GetLastAction(fightID int) (string, error) {
	var log FightLog
	err := database.Get(&log, "SELECT * FROM fight_logs WHERE fight_id = %d ORDER BY created DESC, id DESC LIMIT 1", fightID)
	if err != nil {
		return "", nil // No logs found
	}
	return log.ToString(), nil
}

// Helper methods
func (fl *FightLog) CreatedTime() time.Time {
	return time.Unix(fl.Created, 0)
}

func (fl *FightLog) ToString() string {
	switch fl.Type {
	case ActionAttackHit:
		return fmt.Sprintf("You attacked for %d damage!", fl.Data)
	case ActionAttackMiss:
		return "You missed your attack!"
	case ActionSpellHeal:
		return fmt.Sprintf("You cast %s and healed %d HP!", fl.Name, fl.Data)
	case ActionSpellHurt:
		return fmt.Sprintf("You cast %s and dealt %d damage!", fl.Name, fl.Data)
	case ActionRunSuccess:
		return "You successfully ran away!"
	case ActionRunFail:
		return "You failed to run away!"
	case ActionGeneric:
		return fl.Name
	case ActionMonsterAttack:
		return fmt.Sprintf("%s attacks for %d damage!", fl.Name, fl.Data)
	case ActionMonsterMiss:
		return fmt.Sprintf("%s missed its attack!", fl.Name)
	case ActionMonsterSpell:
		parts := strings.Split(fl.Name, "|")
		if len(parts) == 2 {
			return fmt.Sprintf("%s casts %s for %d damage!", parts[0], parts[1], fl.Data)
		}
		return fmt.Sprintf("%s casts a spell for %d damage!", fl.Name, fl.Data)
	case ActionMonsterDeath:
		return fmt.Sprintf("%s has been defeated!", fl.Name)
	default:
		return "Unknown action"
	}
}
