package session

import (
	"fmt"
	"sync"
	"time"

	"github.com/google/uuid"
)

const MaxSessions = 32

type Manager struct {
	mu       sync.RWMutex
	sessions map[string]*SessionInfo
}

func NewManager() *Manager {
	return &Manager{
		sessions: make(map[string]*SessionInfo),
	}
}

func (m *Manager) Create(connectionID int64, protocol string) (*SessionInfo, error) {
	return m.CreateWithID(uuid.NewString(), connectionID, protocol)
}

// CreateWithID registers a session with an explicit ID (e.g., the SSH session UUID).
// This keeps the session manager in sync with service-level session IDs.
func (m *Manager) CreateWithID(id string, connectionID int64, protocol string) (*SessionInfo, error) {
	m.mu.Lock()
	defer m.mu.Unlock()

	if len(m.sessions) >= MaxSessions {
		return nil, fmt.Errorf("maximum sessions (%d) reached", MaxSessions)
	}

	s := &SessionInfo{
		ID:           id,
		ConnectionID: connectionID,
		Protocol:     protocol,
		State:        StateConnecting,
		TabPosition:  len(m.sessions),
		ConnectedAt:  time.Now(),
	}
	m.sessions[s.ID] = s
	return s, nil
}

func (m *Manager) Get(id string) (*SessionInfo, bool) {
	m.mu.RLock()
	defer m.mu.RUnlock()
	s, ok := m.sessions[id]
	return s, ok
}

func (m *Manager) List() []*SessionInfo {
	m.mu.RLock()
	defer m.mu.RUnlock()
	list := make([]*SessionInfo, 0, len(m.sessions))
	for _, s := range m.sessions {
		list = append(list, s)
	}
	return list
}

func (m *Manager) SetState(id string, state SessionState) error {
	m.mu.Lock()
	defer m.mu.Unlock()
	s, ok := m.sessions[id]
	if !ok {
		return fmt.Errorf("session %s not found", id)
	}
	s.State = state
	return nil
}

func (m *Manager) Detach(id string) error {
	return m.SetState(id, StateDetached)
}

func (m *Manager) Reattach(id, windowID string) error {
	m.mu.Lock()
	defer m.mu.Unlock()
	s, ok := m.sessions[id]
	if !ok {
		return fmt.Errorf("session %s not found", id)
	}
	s.State = StateConnected
	s.WindowID = windowID
	return nil
}

func (m *Manager) Remove(id string) {
	m.mu.Lock()
	defer m.mu.Unlock()
	delete(m.sessions, id)
}

func (m *Manager) Count() int {
	m.mu.RLock()
	defer m.mu.RUnlock()
	return len(m.sessions)
}
