package console

import (
	"sync"

	"github.com/google/uuid"
)

func NewConsoleManager() *ConsoleManager {
	return &ConsoleManager{
		lock:  &sync.RWMutex{},
		store: map[uuid.UUID]*Console{},
	}
}

type ConsoleManager struct {
	lock  *sync.RWMutex
	store map[uuid.UUID]*Console
}

type ConsoleOpenOpts = NewConsoleOpts

func (c *ConsoleManager) Open(uuid uuid.UUID, opts ...ConsoleOpenOpts) (console *Console, err error) {
	c.lock.Lock()
	defer c.lock.Unlock()

	if console, ok := c.store[uuid]; ok {
		console.Close()
	}

	console = NewConsole(uuid, opts...)
	closeCallback := console.closeCallback

	console.closeCallback = func(uuid UUID) {
		if closeCallback != nil {
			closeCallback(uuid)
		}
		c.Close(uuid)
	}

	c.store[uuid] = console

	return console, console.Start()
}

func (c *ConsoleManager) Get(uuid uuid.UUID) *Console {
	c.lock.RLock()
	defer c.lock.RUnlock()

	if console, ok := c.store[uuid]; ok {
		if !console.IsClosed() {
			return console
		}
	}

	return nil
}

func (c *ConsoleManager) List() []*Console {
	c.lock.RLock()
	defer c.lock.RUnlock()

	res := make([]*Console, 0, len(c.store))
	for _, console := range c.store {
		if console.IsClosed() {
			continue
		}
		res = append(res, console)
	}

	return res
}

func (c *ConsoleManager) Close(uuid uuid.UUID) {
	c.lock.Lock()
	defer c.lock.Unlock()

	if console, ok := c.store[uuid]; ok {
		if !console.IsClosed() {
			console.Close()
		}
		delete(c.store, uuid)
	}
}
