package guilds

import (
	"context"
	"fmt"
	"sort"
	"strings"
	"time"
)

// NewGuildList creates a new guild list instance
func NewGuildList() *GuildList {
	return &GuildList{
		guilds: make(map[int32]*Guild),
	}
}

// AddGuild adds a guild to the list
func (gl *GuildList) AddGuild(guild *Guild) {
	gl.mu.Lock()
	defer gl.mu.Unlock()
	gl.guilds[guild.GetID()] = guild
}

// GetGuild retrieves a guild by ID
func (gl *GuildList) GetGuild(guildID int32) *Guild {
	gl.mu.RLock()
	defer gl.mu.RUnlock()
	return gl.guilds[guildID]
}

// RemoveGuild removes a guild from the list
func (gl *GuildList) RemoveGuild(guildID int32) {
	gl.mu.Lock()
	defer gl.mu.Unlock()
	delete(gl.guilds, guildID)
}

// GetAllGuilds returns all guilds
func (gl *GuildList) GetAllGuilds() []*Guild {
	gl.mu.RLock()
	defer gl.mu.RUnlock()

	guilds := make([]*Guild, 0, len(gl.guilds))
	for _, guild := range gl.guilds {
		guilds = append(guilds, guild)
	}

	return guilds
}

// GetGuildCount returns the number of guilds
func (gl *GuildList) GetGuildCount() int {
	gl.mu.RLock()
	defer gl.mu.RUnlock()
	return len(gl.guilds)
}

// FindGuildByName finds a guild by name (case-insensitive)
func (gl *GuildList) FindGuildByName(name string) *Guild {
	gl.mu.RLock()
	defer gl.mu.RUnlock()

	for _, guild := range gl.guilds {
		if strings.EqualFold(guild.GetName(), name) {
			return guild
		}
	}

	return nil
}

// NewGuildManager creates a new guild manager instance
func NewGuildManager(database GuildDatabase, clientManager ClientManager, playerManager PlayerManager) *GuildManager {
	return &GuildManager{
		guildList:     NewGuildList(),
		database:      database,
		clientManager: clientManager,
		playerManager: playerManager,
	}
}

// SetEventHandler sets the guild event handler
func (gm *GuildManager) SetEventHandler(handler GuildEventHandler) {
	gm.eventHandler = handler
}

// SetLogger sets the logger for the manager
func (gm *GuildManager) SetLogger(logger LogHandler) {
	gm.logger = logger
}

// Initialize loads all guilds from the database
func (gm *GuildManager) Initialize(ctx context.Context) error {
	// Load all guilds
	guildData, err := gm.database.LoadGuilds(ctx)
	if err != nil {
		return fmt.Errorf("failed to load guilds: %w", err)
	}

	for _, data := range guildData {
		guild, err := gm.loadGuildFromData(ctx, data)
		if err != nil {
			if gm.logger != nil {
				gm.logger.LogError("guilds", "Failed to load guild %d (%s): %v", data.ID, data.Name, err)
			}
			continue
		}

		gm.guildList.AddGuild(guild)

		if gm.logger != nil {
			gm.logger.LogDebug("guilds", "Loaded guild %d (%s) with %d members",
				guild.GetID(), guild.GetName(), len(guild.GetAllMembers()))
		}
	}

	if gm.logger != nil {
		gm.logger.LogInfo("guilds", "Loaded %d guilds", gm.guildList.GetGuildCount())
	}

	return nil
}

// LoadGuild loads a specific guild by ID
func (gm *GuildManager) LoadGuild(ctx context.Context, guildID int32) (*Guild, error) {
	// Check if already loaded
	if guild := gm.guildList.GetGuild(guildID); guild != nil {
		return guild, nil
	}

	// Load from database
	guildData, err := gm.database.LoadGuild(ctx, guildID)
	if err != nil {
		return nil, fmt.Errorf("failed to load guild data: %w", err)
	}

	guild, err := gm.loadGuildFromData(ctx, *guildData)
	if err != nil {
		return nil, fmt.Errorf("failed to create guild from data: %w", err)
	}

	gm.guildList.AddGuild(guild)
	return guild, nil
}

// CreateGuild creates a new guild
func (gm *GuildManager) CreateGuild(ctx context.Context, name, motd string, leaderCharacterID int32) (*Guild, error) {
	// Validate guild name
	if err := gm.validateGuildName(name); err != nil {
		return nil, err
	}

	// Check if guild name already exists
	if gm.guildList.FindGuildByName(name) != nil {
		return nil, fmt.Errorf("guild name '%s' already exists", name)
	}

	// Get leader player info
	leaderInfo, err := gm.playerManager.GetPlayerInfo(leaderCharacterID)
	if err != nil {
		return nil, fmt.Errorf("failed to get leader info: %w", err)
	}

	// Create guild data
	guildData := GuildData{
		Name:           name,
		MOTD:           motd,
		Level:          1,
		EXPCurrent:     111,
		EXPToNextLevel: 2521,
		FormedDate:     time.Now(),
	}

	// Save to database
	guildID, err := gm.database.CreateGuild(ctx, guildData)
	if err != nil {
		return nil, fmt.Errorf("failed to create guild in database: %w", err)
	}

	guildData.ID = guildID

	// Create guild instance
	guild := NewGuild()
	guild.SetID(guildData.ID)
	guild.SetName(guildData.Name, false)
	guild.SetMOTD(guildData.MOTD, false)
	guild.SetLevel(guildData.Level, false)
	guild.SetEXPCurrent(guildData.EXPCurrent, false)
	guild.SetEXPToNextLevel(guildData.EXPToNextLevel, false)
	guild.SetFormedDate(guildData.FormedDate)

	// Add leader as first member
	leader := NewGuildMember(leaderCharacterID, leaderInfo.CharacterName, RankLeader)
	leader.AccountID = leaderInfo.AccountID
	leader.UpdatePlayerInfo(leaderInfo)

	guild.members[leaderCharacterID] = leader

	// Save member to database
	if err := gm.database.SaveGuildMembers(ctx, guildID, []*GuildMember{leader}); err != nil {
		return nil, fmt.Errorf("failed to save guild leader: %w", err)
	}

	// Add to guild list
	gm.guildList.AddGuild(guild)

	// Add guild creation event
	guild.AddNewGuildEvent(EventGuildLevelUp, fmt.Sprintf("Guild '%s' has been formed by %s", name, leaderInfo.CharacterName), time.Now(), true)

	// Notify event handler
	if gm.eventHandler != nil {
		gm.eventHandler.OnGuildCreated(guild)
	}

	if gm.logger != nil {
		gm.logger.LogInfo("guilds", "Created guild %d (%s) with leader %s (%d)",
			guildID, name, leaderInfo.CharacterName, leaderCharacterID)
	}

	return guild, nil
}

// DeleteGuild deletes a guild
func (gm *GuildManager) DeleteGuild(ctx context.Context, guildID int32, deleterName string) error {
	guild := gm.guildList.GetGuild(guildID)
	if guild == nil {
		return fmt.Errorf("guild %d not found", guildID)
	}

	guildName := guild.GetName()

	// Remove from database
	if err := gm.database.DeleteGuild(ctx, guildID); err != nil {
		return fmt.Errorf("failed to delete guild from database: %w", err)
	}

	// Remove from guild list
	gm.guildList.RemoveGuild(guildID)

	// Notify event handler
	if gm.eventHandler != nil {
		gm.eventHandler.OnGuildDeleted(guildID, guildName)
	}

	if gm.logger != nil {
		gm.logger.LogInfo("guilds", "Deleted guild %d (%s) by %s", guildID, guildName, deleterName)
	}

	return nil
}

// GetGuild returns a guild by ID
func (gm *GuildManager) GetGuild(guildID int32) *Guild {
	return gm.guildList.GetGuild(guildID)
}

// GetGuildByName returns a guild by name
func (gm *GuildManager) GetGuildByName(name string) *Guild {
	return gm.guildList.FindGuildByName(name)
}

// GetAllGuilds returns all guilds
func (gm *GuildManager) GetAllGuilds() []*Guild {
	return gm.guildList.GetAllGuilds()
}

// GetGuildByCharacterID returns the guild for a character
func (gm *GuildManager) GetGuildByCharacterID(ctx context.Context, characterID int32) (*Guild, error) {
	// Try to find in loaded guilds first
	for _, guild := range gm.guildList.GetAllGuilds() {
		if guild.GetGuildMember(characterID) != nil {
			return guild, nil
		}
	}

	// Look up in database
	guildID, err := gm.database.GetGuildIDByCharacterID(ctx, characterID)
	if err != nil {
		return nil, fmt.Errorf("character %d is not in a guild: %w", characterID, err)
	}

	// Load the guild if not already loaded
	return gm.LoadGuild(ctx, guildID)
}

// InvitePlayer invites a player to a guild
func (gm *GuildManager) InvitePlayer(ctx context.Context, guildID, inviterID int32, playerName string, rank int8) error {
	guild := gm.guildList.GetGuild(guildID)
	if guild == nil {
		return fmt.Errorf("guild %d not found", guildID)
	}

	// Validate inviter permissions
	inviter := guild.GetGuildMember(inviterID)
	if inviter == nil {
		return fmt.Errorf("inviter %d is not a guild member", inviterID)
	}

	if guild.GetPermission(inviter.GetRank(), PermissionInvite) == 0 {
		return fmt.Errorf("inviter does not have permission to invite")
	}

	// Validate target player
	targetID, err := gm.playerManager.ValidatePlayerExists(playerName)
	if err != nil {
		return fmt.Errorf("player '%s' not found: %w", playerName, err)
	}

	// Check if player is already in a guild
	if existingGuild, _ := gm.GetGuildByCharacterID(ctx, targetID); existingGuild != nil {
		return fmt.Errorf("player '%s' is already in guild '%s'", playerName, existingGuild.GetName())
	}

	// TODO: Send guild invitation to player
	// This would typically involve sending a packet to the client

	if gm.logger != nil {
		gm.logger.LogDebug("guilds", "Player %s invited to guild %s by %s",
			playerName, guild.GetName(), inviter.GetName())
	}

	return nil
}

// AddMemberToGuild adds a member to a guild
func (gm *GuildManager) AddMemberToGuild(ctx context.Context, guildID, characterID int32, inviterName string, rank int8) error {
	guild := gm.guildList.GetGuild(guildID)
	if guild == nil {
		return fmt.Errorf("guild %d not found", guildID)
	}

	// Check if already a member
	if guild.GetGuildMember(characterID) != nil {
		return fmt.Errorf("character %d is already a guild member", characterID)
	}

	// Get player info
	playerInfo, err := gm.playerManager.GetPlayerInfo(characterID)
	if err != nil {
		return fmt.Errorf("failed to get player info: %w", err)
	}

	// Create guild member
	member := NewGuildMember(characterID, playerInfo.CharacterName, rank)
	member.AccountID = playerInfo.AccountID
	member.UpdatePlayerInfo(playerInfo)

	// Add to guild
	guild.members[characterID] = member
	guild.memberSaveNeeded = true

	// Save to database
	if err := gm.database.SaveGuildMembers(ctx, guildID, []*GuildMember{member}); err != nil {
		return fmt.Errorf("failed to save new guild member: %w", err)
	}

	// Add guild event
	guild.AddNewGuildEvent(EventMemberJoins,
		fmt.Sprintf("%s has joined the guild (invited by %s)", playerInfo.CharacterName, inviterName),
		time.Now(), true)

	// Notify event handler
	if gm.eventHandler != nil {
		gm.eventHandler.OnMemberJoined(guild, member, inviterName)
	}

	if gm.logger != nil {
		gm.logger.LogInfo("guilds", "Player %s (%d) joined guild %s (%d)",
			playerInfo.CharacterName, characterID, guild.GetName(), guildID)
	}

	return nil
}

// RemoveMemberFromGuild removes a member from a guild
func (gm *GuildManager) RemoveMemberFromGuild(ctx context.Context, guildID, characterID int32, removerName, reason string) error {
	guild := gm.guildList.GetGuild(guildID)
	if guild == nil {
		return fmt.Errorf("guild %d not found", guildID)
	}

	member := guild.GetGuildMember(characterID)
	if member == nil {
		return fmt.Errorf("character %d is not a guild member", characterID)
	}

	memberName := member.GetName()

	// Remove from guild
	guild.RemoveGuildMember(characterID, true)

	// Save changes
	if err := gm.saveGuildChanges(ctx, guild); err != nil {
		if gm.logger != nil {
			gm.logger.LogError("guilds", "Failed to save guild after removing member: %v", err)
		}
	}

	// Notify event handler
	if gm.eventHandler != nil {
		gm.eventHandler.OnMemberLeft(guild, member, reason)
	}

	if gm.logger != nil {
		gm.logger.LogInfo("guilds", "Player %s (%d) removed from guild %s (%d) by %s - %s",
			memberName, characterID, guild.GetName(), guildID, removerName, reason)
	}

	return nil
}

// PromoteMember promotes a guild member
func (gm *GuildManager) PromoteMember(ctx context.Context, guildID, characterID int32, promoterName string) error {
	guild := gm.guildList.GetGuild(guildID)
	if guild == nil {
		return fmt.Errorf("guild %d not found", guildID)
	}

	member := guild.GetGuildMember(characterID)
	if member == nil {
		return fmt.Errorf("character %d is not a guild member", characterID)
	}

	oldRank := member.GetRank()
	if oldRank <= RankLeader {
		return fmt.Errorf("cannot promote guild leader")
	}

	// Promote
	if !guild.PromoteGuildMember(characterID, promoterName, true) {
		return fmt.Errorf("failed to promote member")
	}

	// Save changes
	if err := gm.saveGuildChanges(ctx, guild); err != nil {
		if gm.logger != nil {
			gm.logger.LogError("guilds", "Failed to save guild after promotion: %v", err)
		}
	}

	// Notify event handler
	if gm.eventHandler != nil {
		gm.eventHandler.OnMemberPromoted(guild, member, oldRank, member.GetRank(), promoterName)
	}

	return nil
}

// DemoteMember demotes a guild member
func (gm *GuildManager) DemoteMember(ctx context.Context, guildID, characterID int32, demoterName string) error {
	guild := gm.guildList.GetGuild(guildID)
	if guild == nil {
		return fmt.Errorf("guild %d not found", guildID)
	}

	member := guild.GetGuildMember(characterID)
	if member == nil {
		return fmt.Errorf("character %d is not a guild member", characterID)
	}

	oldRank := member.GetRank()
	if oldRank >= RankRecruit {
		return fmt.Errorf("cannot demote recruit further")
	}

	// Demote
	if !guild.DemoteGuildMember(characterID, demoterName, true) {
		return fmt.Errorf("failed to demote member")
	}

	// Save changes
	if err := gm.saveGuildChanges(ctx, guild); err != nil {
		if gm.logger != nil {
			gm.logger.LogError("guilds", "Failed to save guild after demotion: %v", err)
		}
	}

	// Notify event handler
	if gm.eventHandler != nil {
		gm.eventHandler.OnMemberDemoted(guild, member, oldRank, member.GetRank(), demoterName)
	}

	return nil
}

// AwardPoints awards points to guild members
func (gm *GuildManager) AwardPoints(ctx context.Context, guildID int32, characterIDs []int32, points float64, comment, awardedBy string) error {
	guild := gm.guildList.GetGuild(guildID)
	if guild == nil {
		return fmt.Errorf("guild %d not found", guildID)
	}

	for _, characterID := range characterIDs {
		if !guild.AddPointsToGuildMember(characterID, points, awardedBy, comment, true) {
			if gm.logger != nil {
				gm.logger.LogWarning("guilds", "Failed to award points to character %d", characterID)
			}
		}
	}

	// Save changes
	if err := gm.saveGuildChanges(ctx, guild); err != nil {
		if gm.logger != nil {
			gm.logger.LogError("guilds", "Failed to save guild after awarding points: %v", err)
		}
	}

	// Notify event handler
	if gm.eventHandler != nil {
		gm.eventHandler.OnPointsAwarded(guild, characterIDs, points, comment, awardedBy)
	}

	return nil
}

// SaveAllGuilds saves all guilds that need saving
func (gm *GuildManager) SaveAllGuilds(ctx context.Context) error {
	guilds := gm.guildList.GetAllGuilds()

	var saveErrors []error
	for _, guild := range guilds {
		if err := gm.saveGuildChanges(ctx, guild); err != nil {
			saveErrors = append(saveErrors, fmt.Errorf("guild %d: %w", guild.GetID(), err))
		}
	}

	if len(saveErrors) > 0 {
		return fmt.Errorf("failed to save some guilds: %v", saveErrors)
	}

	return nil
}

// SearchGuilds searches for guilds based on criteria
func (gm *GuildManager) SearchGuilds(criteria GuildSearchCriteria) []*Guild {
	guilds := gm.guildList.GetAllGuilds()
	var results []*Guild

	for _, guild := range guilds {
		if gm.matchesSearchCriteria(guild, criteria) {
			results = append(results, guild)
		}
	}

	// Sort by name
	sort.Slice(results, func(i, j int) bool {
		return results[i].GetName() < results[j].GetName()
	})

	return results
}

// GetGuildStatistics returns guild system statistics
func (gm *GuildManager) GetGuildStatistics() GuildStatistics {
	guilds := gm.guildList.GetAllGuilds()

	stats := GuildStatistics{
		TotalGuilds: len(guilds),
	}

	totalMembers := 0
	activeGuilds := 0
	totalEvents := 0
	totalRecruiters := 0
	uniqueAccounts := make(map[int32]bool)
	highestLevel := int8(1)

	for _, guild := range guilds {
		members := guild.GetAllMembers()
		memberCount := len(members)

		totalMembers += memberCount

		if memberCount > 0 {
			activeGuilds++
		}

		// Track unique accounts
		for _, member := range members {
			uniqueAccounts[member.AccountID] = true
			if member.IsRecruiter() {
				totalRecruiters++
			}
		}

		// Guild level
		if guild.GetLevel() > highestLevel {
			highestLevel = guild.GetLevel()
		}

		// Event count (approximate)
		totalEvents += len(guild.guildEvents)
	}

	stats.TotalMembers = totalMembers
	stats.ActiveGuilds = activeGuilds
	stats.TotalEvents = totalEvents
	stats.TotalRecruiters = totalRecruiters
	stats.UniqueAccounts = len(uniqueAccounts)
	stats.HighestGuildLevel = highestLevel

	if len(guilds) > 0 {
		stats.AverageGuildSize = float64(totalMembers) / float64(len(guilds))
	}

	return stats
}

// Helper methods

// loadGuildFromData creates a guild instance from database data
func (gm *GuildManager) loadGuildFromData(ctx context.Context, data GuildData) (*Guild, error) {
	guild := NewGuild()
	guild.SetID(data.ID)
	guild.SetName(data.Name, false)
	guild.SetMOTD(data.MOTD, false)
	guild.SetLevel(data.Level, false)
	guild.SetEXPCurrent(data.EXPCurrent, false)
	guild.SetEXPToNextLevel(data.EXPToNextLevel, false)
	guild.SetFormedDate(data.FormedDate)

	// Load members
	memberData, err := gm.database.LoadGuildMembers(ctx, data.ID)
	if err != nil {
		return nil, fmt.Errorf("failed to load guild members: %w", err)
	}

	for _, md := range memberData {
		member := &GuildMember{
			CharacterID:                  md.CharacterID,
			AccountID:                    md.AccountID,
			RecruiterID:                  md.RecruiterID,
			Name:                         md.Name,
			GuildStatus:                  md.GuildStatus,
			Points:                       md.Points,
			AdventureClass:               md.AdventureClass,
			AdventureLevel:               md.AdventureLevel,
			TradeskillClass:              md.TradeskillClass,
			TradeskillLevel:              md.TradeskillLevel,
			Rank:                         md.Rank,
			MemberFlags:                  md.MemberFlags,
			Zone:                         md.Zone,
			JoinDate:                     md.JoinDate,
			LastLoginDate:                md.LastLoginDate,
			Note:                         md.Note,
			OfficerNote:                  md.OfficerNote,
			RecruiterDescription:         md.RecruiterDescription,
			RecruiterPictureData:         md.RecruiterPictureData,
			RecruitingShowAdventureClass: md.RecruitingShowAdventureClass,
			PointHistory:                 make([]PointHistory, 0),
		}

		// Load point history
		historyData, err := gm.database.LoadPointHistory(ctx, md.CharacterID)
		if err == nil {
			for _, hd := range historyData {
				member.PointHistory = append(member.PointHistory, PointHistory{
					Date:       hd.Date,
					ModifiedBy: hd.ModifiedBy,
					Comment:    hd.Comment,
					Points:     hd.Points,
					SaveNeeded: false,
				})
			}
		}

		guild.members[md.CharacterID] = member
	}

	// Load events
	eventData, err := gm.database.LoadGuildEvents(ctx, data.ID)
	if err == nil {
		for _, ed := range eventData {
			guild.guildEvents = append(guild.guildEvents, GuildEvent{
				EventID:     ed.EventID,
				Date:        ed.Date,
				Type:        ed.Type,
				Description: ed.Description,
				Locked:      ed.Locked,
				SaveNeeded:  false,
			})
		}
	}

	// Load ranks
	rankData, err := gm.database.LoadGuildRanks(ctx, data.ID)
	if err == nil {
		for _, rd := range rankData {
			guild.ranks[rd.Rank] = rd.Name
		}
	}

	// Load permissions
	permissionData, err := gm.database.LoadGuildPermissions(ctx, data.ID)
	if err == nil {
		for _, pd := range permissionData {
			if guild.permissions[pd.Rank] == nil {
				guild.permissions[pd.Rank] = make(map[int8]int8)
			}
			guild.permissions[pd.Rank][pd.Permission] = pd.Value
		}
	}

	// Load event filters
	filterData, err := gm.database.LoadGuildEventFilters(ctx, data.ID)
	if err == nil {
		for _, fd := range filterData {
			if guild.eventFilters[fd.EventID] == nil {
				guild.eventFilters[fd.EventID] = make(map[int8]int8)
			}
			guild.eventFilters[fd.EventID][fd.Category] = fd.Value
		}
	}

	// Load recruiting settings
	recruitingData, err := gm.database.LoadGuildRecruiting(ctx, data.ID)
	if err == nil {
		for _, rd := range recruitingData {
			if rd.Flag < 0 {
				// Description tag (stored with negative flag values)
				guild.recruitingDescTags[-rd.Flag-1] = rd.Value
			} else {
				// Recruiting flag
				guild.recruitingFlags[rd.Flag] = rd.Value
			}
		}
	}

	// Update next event ID
	if len(guild.guildEvents) > 0 {
		maxEventID := int64(0)
		for _, event := range guild.guildEvents {
			if event.EventID > maxEventID {
				maxEventID = event.EventID
			}
		}
		guild.nextEventID = maxEventID + 1
	}

	// Clear save flags
	guild.saveNeeded = false
	guild.memberSaveNeeded = false
	guild.eventsSaveNeeded = false
	guild.ranksSaveNeeded = false
	guild.eventFiltersSaveNeeded = false
	guild.pointsHistorySaveNeeded = false
	guild.recruitingSaveNeeded = false

	return guild, nil
}

// saveGuildChanges saves any pending changes for a guild
func (gm *GuildManager) saveGuildChanges(ctx context.Context, guild *Guild) error {
	var saveErrors []error

	if guild.GetSaveNeeded() {
		if err := gm.database.SaveGuild(ctx, guild); err != nil {
			saveErrors = append(saveErrors, fmt.Errorf("failed to save guild data: %w", err))
		} else {
			guild.SetSaveNeeded(false)
		}
	}

	if guild.memberSaveNeeded {
		members := guild.GetAllMembers()
		if err := gm.database.SaveGuildMembers(ctx, guild.GetID(), members); err != nil {
			saveErrors = append(saveErrors, fmt.Errorf("failed to save guild members: %w", err))
		} else {
			guild.memberSaveNeeded = false
		}
	}

	if guild.eventsSaveNeeded {
		if err := gm.database.SaveGuildEvents(ctx, guild.GetID(), guild.guildEvents); err != nil {
			saveErrors = append(saveErrors, fmt.Errorf("failed to save guild events: %w", err))
		} else {
			guild.eventsSaveNeeded = false
		}
	}

	if guild.ranksSaveNeeded {
		if err := gm.database.SaveGuildRanks(ctx, guild.GetID(), guild.ranks); err != nil {
			saveErrors = append(saveErrors, fmt.Errorf("failed to save guild ranks: %w", err))
		} else {
			guild.ranksSaveNeeded = false
		}
	}

	if guild.eventFiltersSaveNeeded {
		if err := gm.database.SaveGuildEventFilters(ctx, guild.GetID(), guild.eventFilters); err != nil {
			saveErrors = append(saveErrors, fmt.Errorf("failed to save guild event filters: %w", err))
		} else {
			guild.eventFiltersSaveNeeded = false
		}
	}

	if guild.recruitingSaveNeeded {
		if err := gm.database.SaveGuildRecruiting(ctx, guild.GetID(), guild.recruitingFlags, guild.recruitingDescTags); err != nil {
			saveErrors = append(saveErrors, fmt.Errorf("failed to save guild recruiting: %w", err))
		} else {
			guild.recruitingSaveNeeded = false
		}
	}

	if guild.pointsHistorySaveNeeded {
		for _, member := range guild.GetAllMembers() {
			if err := gm.database.SavePointHistory(ctx, member.GetCharacterID(), member.GetPointHistory()); err != nil {
				saveErrors = append(saveErrors, fmt.Errorf("failed to save point history for %d: %w", member.GetCharacterID(), err))
			}
		}
		guild.pointsHistorySaveNeeded = false
	}

	if len(saveErrors) > 0 {
		return fmt.Errorf("save errors: %v", saveErrors)
	}

	return nil
}

// validateGuildName validates a guild name
func (gm *GuildManager) validateGuildName(name string) error {
	if len(strings.TrimSpace(name)) == 0 {
		return fmt.Errorf("guild name cannot be empty")
	}

	if len(name) > MaxGuildNameLength {
		return fmt.Errorf("guild name too long: %d > %d", len(name), MaxGuildNameLength)
	}

	// Check for invalid characters
	if strings.ContainsAny(name, "<>&\"'") {
		return fmt.Errorf("guild name contains invalid characters")
	}

	return nil
}

// matchesSearchCriteria checks if a guild matches search criteria
func (gm *GuildManager) matchesSearchCriteria(guild *Guild, criteria GuildSearchCriteria) bool {
	// Name pattern matching
	if criteria.NamePattern != "" {
		if !strings.Contains(strings.ToLower(guild.GetName()), strings.ToLower(criteria.NamePattern)) {
			return false
		}
	}

	// Level range
	level := guild.GetLevel()
	if criteria.MinLevel > 0 && level < criteria.MinLevel {
		return false
	}
	if criteria.MaxLevel > 0 && level > criteria.MaxLevel {
		return false
	}

	// Member count range
	memberCount := len(guild.GetAllMembers())
	if criteria.MinMembers > 0 && memberCount < criteria.MinMembers {
		return false
	}
	if criteria.MaxMembers > 0 && memberCount > criteria.MaxMembers {
		return false
	}

	// Recruiting only
	if criteria.RecruitingOnly && guild.GetNumRecruiters() == 0 {
		return false
	}

	// Play style
	if criteria.PlayStyle > 0 && guild.GetRecruitingPlayStyle() != criteria.PlayStyle {
		return false
	}

	// Required flags
	for _, flag := range criteria.RequiredFlags {
		if guild.GetRecruitingFlag(flag) == 0 {
			return false
		}
	}

	// Required description tags
	for _, tag := range criteria.RequiredDescTags {
		found := false
		for i := int8(0); i < 4; i++ {
			if guild.GetRecruitingDescTag(i) == tag {
				found = true
				break
			}
		}
		if !found {
			return false
		}
	}

	// Excluded description tags
	for _, tag := range criteria.ExcludedDescTags {
		for i := int8(0); i < 4; i++ {
			if guild.GetRecruitingDescTag(i) == tag {
				return false
			}
		}
	}

	return true
}
