package ai

import (
	"fmt"
	"time"
)

// CombatPetBrain extends the base brain for combat pets
type CombatPetBrain struct {
	*BaseBrain
}

// NewCombatPetBrain creates a new combat pet brain
func NewCombatPetBrain(npc NPC, logger Logger) *CombatPetBrain {
	brain := &CombatPetBrain{
		BaseBrain: NewBaseBrain(npc, logger),
	}
	brain.brainType = BrainTypeCombatPet
	return brain
}

// Think implements pet-specific AI logic
func (cpb *CombatPetBrain) Think() error {
	// Call parent Think() for default combat behavior
	if err := cpb.BaseBrain.Think(); err != nil {
		return err
	}

	// Additional pet-specific logic
	if cpb.npc.GetInCombat() || !cpb.npc.IsPet() || cpb.npc.IsMezzedOrStunned() {
		return nil
	}

	if cpb.logger != nil && cpb.state.GetDebugLevel() >= DebugLevelDetailed {
		cpb.logger.LogDebug("Combat pet AI for %s", cpb.npc.GetName())
	}

	// Check if owner has stay command set
	owner := cpb.npc.GetOwner()
	if owner != nil && owner.IsPlayer() {
		// TODO: Check player's pet movement setting
		// if player.GetInfoStruct().GetPetMovement() == PetMovementStay {
		//     return nil
		// }
	}

	// Follow owner
	if owner != nil {
		cpb.npc.SetTarget(owner)
		distance := cpb.npc.GetDistance(owner)

		maxRange := cpb.getMaxCombatRange()
		if distance > maxRange {
			cpb.MoveCloser(owner)
		}
	}

	return nil
}

// NonCombatPetBrain handles non-combat pets (cosmetic pets)
type NonCombatPetBrain struct {
	*BaseBrain
}

// NewNonCombatPetBrain creates a new non-combat pet brain
func NewNonCombatPetBrain(npc NPC, logger Logger) *NonCombatPetBrain {
	brain := &NonCombatPetBrain{
		BaseBrain: NewBaseBrain(npc, logger),
	}
	brain.brainType = BrainTypeNonCombatPet
	return brain
}

// Think implements non-combat pet AI (just following)
func (ncpb *NonCombatPetBrain) Think() error {
	// Non-combat pets don't do combat AI
	if !ncpb.npc.IsPet() || ncpb.npc.IsMezzedOrStunned() {
		return nil
	}

	if ncpb.logger != nil && ncpb.state.GetDebugLevel() >= DebugLevelDetailed {
		ncpb.logger.LogDebug("Non-combat pet AI for %s", ncpb.npc.GetName())
	}

	// Just follow owner
	owner := ncpb.npc.GetOwner()
	if owner != nil {
		ncpb.npc.SetTarget(owner)
		distance := ncpb.npc.GetDistance(owner)

		maxRange := ncpb.getMaxCombatRange()
		if distance > maxRange {
			ncpb.MoveCloser(owner)
		}
	}

	return nil
}

// BlankBrain provides a minimal AI that does nothing
type BlankBrain struct {
	*BaseBrain
}

// NewBlankBrain creates a new blank brain
func NewBlankBrain(npc NPC, logger Logger) *BlankBrain {
	brain := &BlankBrain{
		BaseBrain: NewBaseBrain(npc, logger),
	}
	brain.brainType = BrainTypeBlank
	brain.SetThinkTick(BlankBrainTick) // Very slow tick
	return brain
}

// Think does nothing for blank brains
func (bb *BlankBrain) Think() error {
	// Blank brain does nothing
	return nil
}

// LuaBrain allows AI to be controlled by Lua scripts
type LuaBrain struct {
	*BaseBrain
	scriptInterface LuaInterface
}

// NewLuaBrain creates a new Lua-controlled brain
func NewLuaBrain(npc NPC, logger Logger, luaInterface LuaInterface) *LuaBrain {
	brain := &LuaBrain{
		BaseBrain:       NewBaseBrain(npc, logger),
		scriptInterface: luaInterface,
	}
	brain.brainType = BrainTypeLua
	return brain
}

// Think calls the Lua script's Think function
func (lb *LuaBrain) Think() error {
	if lb.scriptInterface == nil {
		return fmt.Errorf("no Lua interface available")
	}

	if lb.npc == nil {
		return fmt.Errorf("brain has no body")
	}

	script := lb.npc.GetSpawnScript()
	if script == "" {
		if lb.logger != nil {
			lb.logger.LogError("Lua brain set on spawn without script")
		}
		return fmt.Errorf("no spawn script available")
	}

	// Call the Lua Think function
	target := lb.npc.GetTarget()
	err := lb.scriptInterface.RunSpawnScript(script, "Think", lb.npc, target)
	if err != nil {
		if lb.logger != nil {
			lb.logger.LogError("Lua script Think function failed: %v", err)
		}
		return fmt.Errorf("Lua Think function failed: %w", err)
	}

	return nil
}

// DumbFirePetBrain handles dumbfire pets (temporary combat pets)
type DumbFirePetBrain struct {
	*BaseBrain
	expireTime int64
}

// NewDumbFirePetBrain creates a new dumbfire pet brain
func NewDumbFirePetBrain(npc NPC, target Entity, expireTimeMS int32, logger Logger) *DumbFirePetBrain {
	brain := &DumbFirePetBrain{
		BaseBrain:  NewBaseBrain(npc, logger),
		expireTime: time.Now().UnixMilli() + int64(expireTimeMS),
	}
	brain.brainType = BrainTypeDumbFire

	// Add maximum hate for the target
	if target != nil {
		brain.AddHate(target.GetID(), MaxHateValue)
	}

	return brain
}

// AddHate only allows hate for the initial target
func (dfpb *DumbFirePetBrain) AddHate(entityID int32, hate int32) {
	// Only add hate if we don't already have a target
	if dfpb.GetMostHated() == 0 {
		dfpb.BaseBrain.AddHate(entityID, hate)
	}
}

// Think implements dumbfire pet AI
func (dfpb *DumbFirePetBrain) Think() error {
	// Check if expired
	if time.Now().UnixMilli() > dfpb.expireTime {
		if dfpb.npc != nil && dfpb.npc.GetHP() > 0 {
			if dfpb.logger != nil {
				dfpb.logger.LogDebug("Dumbfire pet %s expired", dfpb.npc.GetName())
			}
			dfpb.npc.KillSpawn(dfpb.npc)
		}
		return nil
	}

	// Get target
	targetID := dfpb.GetMostHated()
	if targetID == 0 {
		// No target, kill self
		if dfpb.npc != nil && dfpb.npc.GetHP() > 0 {
			if dfpb.logger != nil {
				dfpb.logger.LogDebug("Dumbfire pet %s has no target", dfpb.npc.GetName())
			}
			dfpb.npc.KillSpawn(dfpb.npc)
		}
		return nil
	}

	target := dfpb.getEntityByID(targetID)
	if target == nil {
		// Target no longer exists, kill self
		if dfpb.npc != nil && dfpb.npc.GetHP() > 0 {
			dfpb.npc.KillSpawn(dfpb.npc)
		}
		return nil
	}

	// Skip if mezzed or stunned
	if dfpb.npc.IsMezzedOrStunned() {
		return nil
	}

	// Set target if not already set
	if dfpb.npc.GetTarget() != target {
		dfpb.npc.SetTarget(target)
		dfpb.npc.FaceTarget(target, false)
	}

	// Enter combat if not already
	if !dfpb.npc.GetInCombat() {
		dfpb.npc.CalculateRunningLocation(true)
		dfpb.npc.InCombat(true)
	}

	distance := dfpb.npc.GetDistance(target)

	// Try to cast spells if we have line of sight
	if dfpb.npc.CheckLoS(target) && !dfpb.npc.IsCasting() &&
		(!dfpb.HasRecovered() || !dfpb.ProcessSpell(target, distance)) {

		if dfpb.logger != nil && dfpb.state.GetDebugLevel() >= DebugLevelDetailed {
			dfpb.logger.LogDebug("Dumbfire pet %s attempting melee on %s",
				dfpb.npc.GetName(), target.GetName())
		}

		dfpb.npc.FaceTarget(target, false)
		dfpb.ProcessMelee(target, distance)
	}

	return nil
}

// GetExpireTime returns when this dumbfire pet will expire
func (dfpb *DumbFirePetBrain) GetExpireTime() int64 {
	return dfpb.expireTime
}

// SetExpireTime sets when this dumbfire pet will expire
func (dfpb *DumbFirePetBrain) SetExpireTime(expireTime int64) {
	dfpb.expireTime = expireTime
}

// IsExpired checks if the dumbfire pet has expired
func (dfpb *DumbFirePetBrain) IsExpired() bool {
	return time.Now().UnixMilli() > dfpb.expireTime
}

// ExtendExpireTime extends the expire time by the given duration
func (dfpb *DumbFirePetBrain) ExtendExpireTime(durationMS int32) {
	dfpb.expireTime += int64(durationMS)
}

// Brain factory functions

// CreateBrain creates the appropriate brain type for an NPC
func CreateBrain(npc NPC, brainType int8, logger Logger, options ...interface{}) Brain {
	switch brainType {
	case BrainTypeCombatPet:
		return NewCombatPetBrain(npc, logger)

	case BrainTypeNonCombatPet:
		return NewNonCombatPetBrain(npc, logger)

	case BrainTypeBlank:
		return NewBlankBrain(npc, logger)

	case BrainTypeLua:
		if len(options) > 0 {
			if luaInterface, ok := options[0].(LuaInterface); ok {
				return NewLuaBrain(npc, logger, luaInterface)
			}
		}
		return NewBaseBrain(npc, logger) // Fallback to default

	case BrainTypeDumbFire:
		if len(options) >= 2 {
			if target, ok := options[0].(Entity); ok {
				if expireTime, ok := options[1].(int32); ok {
					return NewDumbFirePetBrain(npc, target, expireTime, logger)
				}
			}
		}
		return NewBaseBrain(npc, logger) // Fallback to default

	default:
		return NewBaseBrain(npc, logger)
	}
}
