package guilds

import (
	"time"
)

// NewGuildMember creates a new guild member instance
func NewGuildMember(characterID int32, name string, rank int8) *GuildMember {
	return &GuildMember{
		CharacterID:                  characterID,
		Name:                         name,
		Rank:                         rank,
		JoinDate:                     time.Now(),
		LastLoginDate:                time.Now(),
		PointHistory:                 make([]PointHistory, 0),
		RecruitingShowAdventureClass: 1,
	}
}

// GetCharacterID returns the character ID
func (gm *GuildMember) GetCharacterID() int32 {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.CharacterID
}

// GetName returns the member name
func (gm *GuildMember) GetName() string {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.Name
}

// SetName sets the member name
func (gm *GuildMember) SetName(name string) {
	gm.mu.Lock()
	defer gm.mu.Unlock()
	if len(name) > MaxMemberNameLength {
		name = name[:MaxMemberNameLength]
	}
	gm.Name = name
}

// GetRank returns the member rank
func (gm *GuildMember) GetRank() int8 {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.Rank
}

// SetRank sets the member rank
func (gm *GuildMember) SetRank(rank int8) {
	gm.mu.Lock()
	defer gm.mu.Unlock()
	if rank >= RankLeader && rank <= RankRecruit {
		gm.Rank = rank
	}
}

// GetPoints returns the member's guild points
func (gm *GuildMember) GetPoints() float64 {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.Points
}

// SetPoints sets the member's guild points
func (gm *GuildMember) SetPoints(points float64) {
	gm.mu.Lock()
	defer gm.mu.Unlock()
	gm.Points = points
}

// AddPoints adds points to the member
func (gm *GuildMember) AddPoints(points float64) {
	gm.mu.Lock()
	defer gm.mu.Unlock()
	gm.Points += points
}

// GetAdventureLevel returns the adventure level
func (gm *GuildMember) GetAdventureLevel() int8 {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.AdventureLevel
}

// SetAdventureLevel sets the adventure level
func (gm *GuildMember) SetAdventureLevel(level int8) {
	gm.mu.Lock()
	defer gm.mu.Unlock()
	gm.AdventureLevel = level
}

// GetAdventureClass returns the adventure class
func (gm *GuildMember) GetAdventureClass() int8 {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.AdventureClass
}

// SetAdventureClass sets the adventure class
func (gm *GuildMember) SetAdventureClass(class int8) {
	gm.mu.Lock()
	defer gm.mu.Unlock()
	gm.AdventureClass = class
}

// GetTradeskillLevel returns the tradeskill level
func (gm *GuildMember) GetTradeskillLevel() int8 {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.TradeskillLevel
}

// SetTradeskillLevel sets the tradeskill level
func (gm *GuildMember) SetTradeskillLevel(level int8) {
	gm.mu.Lock()
	defer gm.mu.Unlock()
	gm.TradeskillLevel = level
}

// GetTradeskillClass returns the tradeskill class
func (gm *GuildMember) GetTradeskillClass() int8 {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.TradeskillClass
}

// SetTradeskillClass sets the tradeskill class
func (gm *GuildMember) SetTradeskillClass(class int8) {
	gm.mu.Lock()
	defer gm.mu.Unlock()
	gm.TradeskillClass = class
}

// GetZone returns the member's current zone
func (gm *GuildMember) GetZone() string {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.Zone
}

// SetZone sets the member's current zone
func (gm *GuildMember) SetZone(zone string) {
	gm.mu.Lock()
	defer gm.mu.Unlock()
	gm.Zone = zone
}

// GetJoinDate returns when the member joined the guild
func (gm *GuildMember) GetJoinDate() time.Time {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.JoinDate
}

// SetJoinDate sets when the member joined the guild
func (gm *GuildMember) SetJoinDate(date time.Time) {
	gm.mu.Lock()
	defer gm.mu.Unlock()
	gm.JoinDate = date
}

// GetLastLoginDate returns the member's last login date
func (gm *GuildMember) GetLastLoginDate() time.Time {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.LastLoginDate
}

// SetLastLoginDate sets the member's last login date
func (gm *GuildMember) SetLastLoginDate(date time.Time) {
	gm.mu.Lock()
	defer gm.mu.Unlock()
	gm.LastLoginDate = date
}

// GetNote returns the member's personal note
func (gm *GuildMember) GetNote() string {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.Note
}

// SetNote sets the member's personal note
func (gm *GuildMember) SetNote(note string) {
	gm.mu.Lock()
	defer gm.mu.Unlock()
	gm.Note = note
}

// GetOfficerNote returns the member's officer note
func (gm *GuildMember) GetOfficerNote() string {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.OfficerNote
}

// SetOfficerNote sets the member's officer note
func (gm *GuildMember) SetOfficerNote(note string) {
	gm.mu.Lock()
	defer gm.mu.Unlock()
	gm.OfficerNote = note
}

// GetMemberFlags returns the member flags
func (gm *GuildMember) GetMemberFlags() int8 {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.MemberFlags
}

// SetMemberFlags sets the member flags
func (gm *GuildMember) SetMemberFlags(flags int8) {
	gm.mu.Lock()
	defer gm.mu.Unlock()
	gm.MemberFlags = flags
}

// HasMemberFlag checks if the member has a specific flag
func (gm *GuildMember) HasMemberFlag(flag int8) bool {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.MemberFlags&flag != 0
}

// SetMemberFlag sets or unsets a specific member flag
func (gm *GuildMember) SetMemberFlag(flag int8, value bool) {
	gm.mu.Lock()
	defer gm.mu.Unlock()

	if value {
		gm.MemberFlags |= flag
	} else {
		gm.MemberFlags &^= flag
	}
}

// IsRecruiter checks if the member is a recruiter
func (gm *GuildMember) IsRecruiter() bool {
	return gm.HasMemberFlag(MemberFlagRecruitingForGuild)
}

// SetRecruiter sets or unsets the recruiter flag
func (gm *GuildMember) SetRecruiter(isRecruiter bool) {
	gm.SetMemberFlag(MemberFlagRecruitingForGuild, isRecruiter)
}

// GetRecruiterID returns the recruiter ID
func (gm *GuildMember) GetRecruiterID() int32 {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.RecruiterID
}

// SetRecruiterID sets the recruiter ID
func (gm *GuildMember) SetRecruiterID(id int32) {
	gm.mu.Lock()
	defer gm.mu.Unlock()
	gm.RecruiterID = id
}

// GetRecruiterDescription returns the recruiter description
func (gm *GuildMember) GetRecruiterDescription() string {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.RecruiterDescription
}

// SetRecruiterDescription sets the recruiter description
func (gm *GuildMember) SetRecruiterDescription(description string) {
	gm.mu.Lock()
	defer gm.mu.Unlock()
	gm.RecruiterDescription = description
}

// GetRecruiterPictureData returns the recruiter picture data
func (gm *GuildMember) GetRecruiterPictureData() []byte {
	gm.mu.RLock()
	defer gm.mu.RUnlock()

	// Return a copy to prevent external modification
	if gm.RecruiterPictureData == nil {
		return nil
	}

	data := make([]byte, len(gm.RecruiterPictureData))
	copy(data, gm.RecruiterPictureData)
	return data
}

// SetRecruiterPictureData sets the recruiter picture data
func (gm *GuildMember) SetRecruiterPictureData(data []byte) {
	gm.mu.Lock()
	defer gm.mu.Unlock()

	if data == nil {
		gm.RecruiterPictureData = nil
		return
	}

	// Make a copy to prevent external modification
	gm.RecruiterPictureData = make([]byte, len(data))
	copy(gm.RecruiterPictureData, data)
}

// GetRecruitingShowAdventureClass returns whether to show adventure class
func (gm *GuildMember) GetRecruitingShowAdventureClass() bool {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.RecruitingShowAdventureClass != 0
}

// SetRecruitingShowAdventureClass sets whether to show adventure class
func (gm *GuildMember) SetRecruitingShowAdventureClass(show bool) {
	gm.mu.Lock()
	defer gm.mu.Unlock()

	if show {
		gm.RecruitingShowAdventureClass = 1
	} else {
		gm.RecruitingShowAdventureClass = 0
	}
}

// GetPointHistory returns a copy of the point history
func (gm *GuildMember) GetPointHistory() []PointHistory {
	gm.mu.RLock()
	defer gm.mu.RUnlock()

	history := make([]PointHistory, len(gm.PointHistory))
	copy(history, gm.PointHistory)
	return history
}

// AddPointHistory adds a point history entry
func (gm *GuildMember) AddPointHistory(date time.Time, modifiedBy string, points float64, comment string) {
	gm.mu.Lock()
	defer gm.mu.Unlock()

	// Limit history size
	if len(gm.PointHistory) >= MaxPointHistory {
		// Remove oldest entry
		gm.PointHistory = gm.PointHistory[1:]
	}

	history := PointHistory{
		Date:       date,
		ModifiedBy: modifiedBy,
		Points:     points,
		Comment:    comment,
		SaveNeeded: true,
	}

	gm.PointHistory = append(gm.PointHistory, history)
}

// GetMemberInfo returns formatted member information
func (gm *GuildMember) GetMemberInfo(rankName string, isOnline bool) MemberInfo {
	gm.mu.RLock()
	defer gm.mu.RUnlock()

	return MemberInfo{
		CharacterID:     gm.CharacterID,
		Name:            gm.Name,
		Rank:            gm.Rank,
		RankName:        rankName,
		Points:          gm.Points,
		AdventureClass:  gm.AdventureClass,
		AdventureLevel:  gm.AdventureLevel,
		TradeskillClass: gm.TradeskillClass,
		TradeskillLevel: gm.TradeskillLevel,
		Zone:            gm.Zone,
		JoinDate:        gm.JoinDate,
		LastLoginDate:   gm.LastLoginDate,
		IsOnline:        isOnline,
		IsRecruiter:     gm.MemberFlags&MemberFlagRecruitingForGuild != 0,
		Note:            gm.Note,
		OfficerNote:     gm.OfficerNote,
	}
}

// GetRecruiterInfo returns formatted recruiter information
func (gm *GuildMember) GetRecruiterInfo(isOnline bool) RecruiterInfo {
	gm.mu.RLock()
	defer gm.mu.RUnlock()

	return RecruiterInfo{
		CharacterID:        gm.CharacterID,
		Name:               gm.Name,
		Description:        gm.RecruiterDescription,
		PictureData:        gm.GetRecruiterPictureData(), // This will make a copy
		ShowAdventureClass: gm.RecruitingShowAdventureClass != 0,
		AdventureClass:     gm.AdventureClass,
		IsOnline:           isOnline,
	}
}

// UpdatePlayerInfo updates member info from player data
func (gm *GuildMember) UpdatePlayerInfo(playerInfo PlayerInfo) {
	gm.mu.Lock()
	defer gm.mu.Unlock()

	gm.AdventureLevel = playerInfo.AdventureLevel
	gm.AdventureClass = playerInfo.AdventureClass
	gm.TradeskillLevel = playerInfo.TradeskillLevel
	gm.TradeskillClass = playerInfo.TradeskillClass
	gm.Zone = playerInfo.Zone

	if playerInfo.IsOnline {
		gm.LastLoginDate = time.Now()
	}
}

// ValidateRank checks if the rank is valid
func (gm *GuildMember) ValidateRank() bool {
	gm.mu.RLock()
	defer gm.mu.RUnlock()
	return gm.Rank >= RankLeader && gm.Rank <= RankRecruit
}

// CanPromote checks if this member can promote another member
func (gm *GuildMember) CanPromote(targetRank int8) bool {
	gm.mu.RLock()
	defer gm.mu.RUnlock()

	// Can only promote members with lower rank (higher rank number)
	// Cannot promote to same or higher rank than self
	return gm.Rank < targetRank && targetRank > RankLeader
}

// CanDemote checks if this member can demote another member
func (gm *GuildMember) CanDemote(targetRank int8) bool {
	gm.mu.RLock()
	defer gm.mu.RUnlock()

	// Can only demote members with equal or lower rank (same or higher rank number)
	// Cannot demote to recruit (already lowest)
	return gm.Rank <= targetRank && targetRank < RankRecruit
}

// CanKick checks if this member can kick another member
func (gm *GuildMember) CanKick(targetRank int8) bool {
	gm.mu.RLock()
	defer gm.mu.RUnlock()

	// Can only kick members with lower rank (higher rank number)
	return gm.Rank < targetRank
}

// Copy creates a deep copy of the guild member
func (gm *GuildMember) Copy() *GuildMember {
	gm.mu.RLock()
	defer gm.mu.RUnlock()

	newMember := &GuildMember{
		CharacterID:                  gm.CharacterID,
		AccountID:                    gm.AccountID,
		RecruiterID:                  gm.RecruiterID,
		Name:                         gm.Name,
		GuildStatus:                  gm.GuildStatus,
		Points:                       gm.Points,
		AdventureClass:               gm.AdventureClass,
		AdventureLevel:               gm.AdventureLevel,
		TradeskillClass:              gm.TradeskillClass,
		TradeskillLevel:              gm.TradeskillLevel,
		Rank:                         gm.Rank,
		MemberFlags:                  gm.MemberFlags,
		Zone:                         gm.Zone,
		JoinDate:                     gm.JoinDate,
		LastLoginDate:                gm.LastLoginDate,
		Note:                         gm.Note,
		OfficerNote:                  gm.OfficerNote,
		RecruiterDescription:         gm.RecruiterDescription,
		RecruitingShowAdventureClass: gm.RecruitingShowAdventureClass,
		PointHistory:                 make([]PointHistory, len(gm.PointHistory)),
	}

	// Deep copy point history
	copy(newMember.PointHistory, gm.PointHistory)

	// Deep copy picture data
	if gm.RecruiterPictureData != nil {
		newMember.RecruiterPictureData = make([]byte, len(gm.RecruiterPictureData))
		copy(newMember.RecruiterPictureData, gm.RecruiterPictureData)
	}

	return newMember
}
