package groups

import (
	"sync"
	"time"

	"eq2emu/internal/entity"
)

// GroupOptions holds group configuration settings
type GroupOptions struct {
	LootMethod      int8 `json:"loot_method"`
	LootItemsRarity int8 `json:"loot_items_rarity"`
	AutoSplit       int8 `json:"auto_split"`
	DefaultYell     int8 `json:"default_yell"`
	GroupLockMethod int8 `json:"group_lock_method"`
	GroupAutolock   int8 `json:"group_autolock"`
	SoloAutolock    int8 `json:"solo_autolock"`
	AutoLootMethod  int8 `json:"auto_loot_method"`
	LastLootedIndex int8 `json:"last_looted_index"`
}

// GroupMemberInfo contains all information about a group member
type GroupMemberInfo struct {
	// Group and member identification
	GroupID int32  `json:"group_id"`
	Name    string `json:"name"`
	Zone    string `json:"zone"`

	// Health and power stats
	HPCurrent    int32 `json:"hp_current"`
	HPMax        int32 `json:"hp_max"`
	PowerCurrent int32 `json:"power_current"`
	PowerMax     int32 `json:"power_max"`

	// Level and character info
	LevelCurrent int16 `json:"level_current"`
	LevelMax     int16 `json:"level_max"`
	RaceID       int8  `json:"race_id"`
	ClassID      int8  `json:"class_id"`

	// Group status
	Leader       bool `json:"leader"`
	IsClient     bool `json:"is_client"`
	IsRaidLooter bool `json:"is_raid_looter"`

	// Zone and instance info
	ZoneID     int32 `json:"zone_id"`
	InstanceID int32 `json:"instance_id"`

	// Mentoring
	MentorTargetCharID int32 `json:"mentor_target_char_id"`

	// Network info for cross-server groups
	ClientPeerAddress string `json:"client_peer_address"`
	ClientPeerPort    int16  `json:"client_peer_port"`

	// Entity reference (local members only)
	Member entity.Entity `json:"-"`

	// Client reference (players only) - interface to avoid circular deps
	Client interface{} `json:"-"`

	// Timestamps
	JoinTime   time.Time `json:"join_time"`
	LastUpdate time.Time `json:"last_update"`
}

// Group represents a player group
type Group struct {
	// Group identification
	id int32

	// Group options and configuration
	options      GroupOptions
	optionsMutex sync.RWMutex

	// Group members
	members      []*GroupMemberInfo
	membersMutex sync.RWMutex

	// Raid functionality
	raidGroups      []int32
	raidGroupsMutex sync.RWMutex

	// Group statistics
	createdTime  time.Time
	lastActivity time.Time

	// Group status
	disbanded    bool
	disbandMutex sync.RWMutex

	// Communication channels
	messageQueue chan *GroupMessage
	updateQueue  chan *GroupUpdate

	// Background processing
	stopChan chan struct{}
	wg       sync.WaitGroup
}

// GroupMessage represents a message sent to the group
type GroupMessage struct {
	Type          int8        `json:"type"`
	Channel       int16       `json:"channel"`
	Message       string      `json:"message"`
	FromName      string      `json:"from_name"`
	Language      int32       `json:"language"`
	Timestamp     time.Time   `json:"timestamp"`
	ExcludeClient interface{} `json:"-"`
}

// GroupUpdate represents a group update event
type GroupUpdate struct {
	Type            int8             `json:"type"`
	GroupID         int32            `json:"group_id"`
	MemberInfo      *GroupMemberInfo `json:"member_info,omitempty"`
	Options         *GroupOptions    `json:"options,omitempty"`
	RaidGroups      []int32          `json:"raid_groups,omitempty"`
	ForceRaidUpdate bool             `json:"force_raid_update"`
	ExcludeClient   interface{}      `json:"-"`
	Timestamp       time.Time        `json:"timestamp"`
}

// GroupInvite represents a pending group invitation
type GroupInvite struct {
	InviterName  string    `json:"inviter_name"`
	InviteeName  string    `json:"invitee_name"`
	GroupID      int32     `json:"group_id"`
	IsRaidInvite bool      `json:"is_raid_invite"`
	CreatedTime  time.Time `json:"created_time"`
	ExpiresTime  time.Time `json:"expires_time"`
}

// GroupManager manages all player groups
type GroupManager struct {
	// Group storage
	groups      map[int32]*Group
	groupsMutex sync.RWMutex

	// Group ID generation
	nextGroupID      int32
	nextGroupIDMutex sync.Mutex

	// Pending invitations
	pendingInvites     map[string]*GroupInvite
	raidPendingInvites map[string]*GroupInvite
	invitesMutex       sync.RWMutex

	// Event handlers
	eventHandlers      []GroupEventHandler
	eventHandlersMutex sync.RWMutex

	// Configuration
	config GroupManagerConfig

	// Statistics
	stats      GroupManagerStats
	statsMutex sync.RWMutex

	// Background processing
	stopChan chan struct{}
	wg       sync.WaitGroup

	// Integration interfaces
	database      GroupDatabase
	packetHandler GroupPacketHandler
	validator     GroupValidator
	notifier      GroupNotifier
}

// GroupManagerConfig holds configuration for the group manager
type GroupManagerConfig struct {
	MaxGroups          int32         `json:"max_groups"`
	MaxRaidGroups      int32         `json:"max_raid_groups"`
	InviteTimeout      time.Duration `json:"invite_timeout"`
	UpdateInterval     time.Duration `json:"update_interval"`
	BuffUpdateInterval time.Duration `json:"buff_update_interval"`
	EnableCrossServer  bool          `json:"enable_cross_server"`
	EnableRaids        bool          `json:"enable_raids"`
	EnableQuestSharing bool          `json:"enable_quest_sharing"`
	EnableAutoInvite   bool          `json:"enable_auto_invite"`
	EnableStatistics   bool          `json:"enable_statistics"`
}

// GroupManagerStats holds statistics about group management
type GroupManagerStats struct {
	TotalGroups          int64         `json:"total_groups"`
	ActiveGroups         int64         `json:"active_groups"`
	TotalRaids           int64         `json:"total_raids"`
	ActiveRaids          int64         `json:"active_raids"`
	TotalInvites         int64         `json:"total_invites"`
	AcceptedInvites      int64         `json:"accepted_invites"`
	DeclinedInvites      int64         `json:"declined_invites"`
	ExpiredInvites       int64         `json:"expired_invites"`
	AverageGroupSize     float64       `json:"average_group_size"`
	AverageGroupDuration time.Duration `json:"average_group_duration"`
	LastStatsUpdate      time.Time     `json:"last_stats_update"`
}

// Default group options
func DefaultGroupOptions() GroupOptions {
	return GroupOptions{
		LootMethod:      LOOT_METHOD_ROUND_ROBIN,
		LootItemsRarity: LOOT_RARITY_COMMON,
		AutoSplit:       AUTO_SPLIT_DISABLED,
		DefaultYell:     DEFAULT_YELL_DISABLED,
		GroupLockMethod: LOCK_METHOD_OPEN,
		GroupAutolock:   AUTO_LOCK_DISABLED,
		SoloAutolock:    AUTO_LOCK_DISABLED,
		AutoLootMethod:  AUTO_LOOT_DISABLED,
		LastLootedIndex: 0,
	}
}

// Copy creates a copy of GroupMemberInfo
func (gmi *GroupMemberInfo) Copy() *GroupMemberInfo {
	copy := *gmi
	return &copy
}

// IsValid checks if the group member info is valid
func (gmi *GroupMemberInfo) IsValid() bool {
	return gmi.GroupID > 0 && len(gmi.Name) > 0
}

// UpdateStats updates member stats from entity
func (gmi *GroupMemberInfo) UpdateStats() {
	if gmi.Member == nil {
		return
	}

	entity := gmi.Member
	gmi.HPCurrent = entity.GetHP()
	gmi.HPMax = entity.GetTotalHP()
	gmi.PowerCurrent = entity.GetPower()
	gmi.PowerMax = entity.GetTotalPower()
	gmi.LevelCurrent = int16(entity.GetLevel())
	gmi.LevelMax = int16(entity.GetLevel()) // TODO: Get actual max level
	gmi.LastUpdate = time.Now()

	// Update zone info if entity has zone
	if zone := entity.GetZone(); zone != nil {
		gmi.ZoneID = zone.GetZoneID()
		gmi.InstanceID = zone.GetInstanceID()
		gmi.Zone = zone.GetZoneName()
	}
}

// Copy creates a copy of GroupOptions
func (go_opts *GroupOptions) Copy() GroupOptions {
	return *go_opts
}

// IsValid checks if group options are valid
func (go_opts *GroupOptions) IsValid() bool {
	return go_opts.LootMethod >= LOOT_METHOD_LEADER_ONLY && go_opts.LootMethod <= LOOT_METHOD_LOTTO &&
		go_opts.LootItemsRarity >= LOOT_RARITY_COMMON && go_opts.LootItemsRarity <= LOOT_RARITY_FABLED
}

// NewGroupMessage creates a new group message
func NewGroupMessage(msgType int8, channel int16, message, fromName string, language int32) *GroupMessage {
	return &GroupMessage{
		Type:      msgType,
		Channel:   channel,
		Message:   message,
		FromName:  fromName,
		Language:  language,
		Timestamp: time.Now(),
	}
}

// NewGroupUpdate creates a new group update
func NewGroupUpdate(updateType int8, groupID int32) *GroupUpdate {
	return &GroupUpdate{
		Type:      updateType,
		GroupID:   groupID,
		Timestamp: time.Now(),
	}
}

// IsExpired checks if the group invite has expired
func (gi *GroupInvite) IsExpired() bool {
	return time.Now().After(gi.ExpiresTime)
}

// TimeRemaining returns the remaining time for the invite
func (gi *GroupInvite) TimeRemaining() time.Duration {
	return gi.ExpiresTime.Sub(time.Now())
}
