package ssmapi

import (
	"sync"

	"github.com/sagernet/sing-box/adapter"
	E "github.com/sagernet/sing/common/exceptions"
)

type UserManager struct {
	access         sync.Mutex
	usersMap       map[string]string
	server         adapter.ManagedSSMServer
	trafficManager *TrafficManager
}

func NewUserManager(inbound adapter.ManagedSSMServer, trafficManager *TrafficManager) *UserManager {
	return &UserManager{
		usersMap:       make(map[string]string),
		server:         inbound,
		trafficManager: trafficManager,
	}
}

func (m *UserManager) postUpdate() error {
	users := make([]string, 0, len(m.usersMap))
	uPSKs := make([]string, 0, len(m.usersMap))
	for username, password := range m.usersMap {
		users = append(users, username)
		uPSKs = append(uPSKs, password)
	}
	err := m.server.UpdateUsers(users, uPSKs)
	if err != nil {
		return err
	}
	m.trafficManager.UpdateUsers(users)
	return nil
}

func (m *UserManager) List() []*UserObject {
	m.access.Lock()
	defer m.access.Unlock()

	users := make([]*UserObject, 0, len(m.usersMap))
	for username, password := range m.usersMap {
		users = append(users, &UserObject{
			UserName: username,
			Password: password,
		})
	}
	return users
}

func (m *UserManager) Add(username string, password string) error {
	m.access.Lock()
	defer m.access.Unlock()
	if _, found := m.usersMap[username]; found {
		return E.New("user ", username, " already exists")
	}
	m.usersMap[username] = password
	return m.postUpdate()
}

func (m *UserManager) Get(username string) (string, bool) {
	m.access.Lock()
	defer m.access.Unlock()
	if password, found := m.usersMap[username]; found {
		return password, true
	}
	return "", false
}

func (m *UserManager) Update(username string, password string) error {
	m.access.Lock()
	defer m.access.Unlock()
	m.usersMap[username] = password
	return m.postUpdate()
}

func (m *UserManager) Delete(username string) error {
	m.access.Lock()
	defer m.access.Unlock()
	delete(m.usersMap, username)
	return m.postUpdate()
}
