package channel import ( "errors" "fmt" "sync" "time" "github.com/google/uuid" ) var ( ErrChannelNotFound = errors.New("channel not found") ErrChannelAlreadyExists = errors.New("channel already exists") ErrChannelFull = errors.New("channel is full") ErrInvalidChannelName = errors.New("invalid channel name") ErrUserNotInChannel = errors.New("user not in channel") ) // Manager manages all channels type Manager struct { channels map[string]*Channel names map[string]bool // for duplicate checking mu sync.RWMutex } // NewManager creates a new channel manager func NewManager() *Manager { return &Manager{ channels: make(map[string]*Channel), names: make(map[string]bool), } } // CreateChannel creates a new channel func (m *Manager) CreateChannel(name string, ownerID string) (*Channel, error) { if name == "" || len(name) < 2 || len(name) > 50 { return nil, ErrInvalidChannelName } m.mu.Lock() defer m.mu.Unlock() if m.names[name] { return nil, ErrChannelAlreadyExists } id := uuid.New().String() channel := NewChannel(id, name, ownerID) channel.AddMember(ownerID) // Owner is automatically a member m.channels[id] = channel m.names[name] = true return channel, nil } // GetChannel retrieves a channel by ID func (m *Manager) GetChannel(channelID string) (*Channel, error) { m.mu.RLock() defer m.mu.RUnlock() channel, exists := m.channels[channelID] if !exists { return nil, ErrChannelNotFound } return channel, nil } // ListChannels returns all active channels func (m *Manager) ListChannels() []*Channel { m.mu.RLock() defer m.mu.RUnlock() channels := make([]*Channel, 0, len(m.channels)) for _, ch := range m.channels { if ch.Status == StatusActive { channels = append(channels, ch) } } return channels } // DeleteChannel deletes a channel (soft or hard delete) func (m *Manager) DeleteChannel(channelID string, hardDelete bool) error { m.mu.Lock() defer m.mu.Unlock() channel, exists := m.channels[channelID] if !exists { return ErrChannelNotFound } if hardDelete { delete(m.channels, channelID) delete(m.names, channel.Name) } else { // Soft delete (archive) channel.Status = StatusArchived channel.UpdatedAt = time.Now() } return nil } // JoinChannel adds a user to a channel func (m *Manager) JoinChannel(channelID string, userID string) (*Channel, error) { m.mu.Lock() defer m.mu.Unlock() channel, exists := m.channels[channelID] if !exists { return nil, ErrChannelNotFound } if channel.Status != StatusActive { return nil, fmt.Errorf("cannot join inactive channel") } if channel.IsFull() { return nil, ErrChannelFull } channel.AddMember(userID) return channel, nil } // LeaveChannel removes a user from a channel func (m *Manager) LeaveChannel(channelID string, userID string) error { m.mu.Lock() defer m.mu.Unlock() channel, exists := m.channels[channelID] if !exists { return ErrChannelNotFound } if !channel.IsMember(userID) { return ErrUserNotInChannel } channel.RemoveMember(userID) return nil } // GetChannelMembers returns members of a channel func (m *Manager) GetChannelMembers(channelID string) ([]string, error) { m.mu.RLock() defer m.mu.RUnlock() channel, exists := m.channels[channelID] if !exists { return nil, ErrChannelNotFound } return channel.GetMembers(), nil } // UpdateChannel updates channel properties func (m *Manager) UpdateChannel(channelID string, name string, description string, isPublic bool, maxUsers int32) (*Channel, error) { m.mu.Lock() defer m.mu.Unlock() channel, exists := m.channels[channelID] if !exists { return nil, ErrChannelNotFound } // Check name uniqueness if changing name if name != "" && name != channel.Name { if m.names[name] { return nil, ErrChannelAlreadyExists } delete(m.names, channel.Name) m.names[name] = true channel.Name = name } if description != "" { channel.Description = description } channel.IsPublic = isPublic channel.MaxUsers = maxUsers channel.UpdatedAt = time.Now() return channel, nil } // IsUserInChannel checks if user is in channel func (m *Manager) IsUserInChannel(channelID string, userID string) bool { m.mu.RLock() defer m.mu.RUnlock() channel, exists := m.channels[channelID] if !exists { return false } return channel.IsMember(userID) } // GetUserChannels returns all channels a user is in func (m *Manager) GetUserChannels(userID string) []*Channel { m.mu.RLock() defer m.mu.RUnlock() var channels []*Channel for _, ch := range m.channels { if ch.Status == StatusActive && ch.IsMember(userID) { channels = append(channels, ch) } } return channels }