package internal

import (
	"context"
	"sync"
)

type StatusType string

const (
	StatusIdle StatusType = "Idle"

	StatusConnecting  StatusType = "Connecting"
	StatusConnected   StatusType = "Connected"
	StatusNeedsLogin  StatusType = "NeedsLogin"
	StatusLoginFailed StatusType = "LoginFailed"
)

// CtxInitState setup context state into the context tree.
//
// This function should be used to initialize context before
// CtxGetState will be executed.
func CtxInitState(ctx context.Context) context.Context {
	return context.WithValue(ctx, stateCtx, &contextState{
		status: StatusIdle,
	})
}

// CtxGetState object to get/update state/errors of process.
func CtxGetState(ctx context.Context) *contextState {
	return ctx.Value(stateCtx).(*contextState)
}

type contextState struct {
	err    error
	status StatusType
	mutex  sync.Mutex
}

func (c *contextState) Set(update StatusType) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.status = update
	c.err = nil
}

func (c *contextState) Status() (StatusType, error) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if c.err != nil {
		return "", c.err
	}

	return c.status, nil
}

func (c *contextState) Wrap(err error) error {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.err = err
	return err
}

type stateKey int

var stateCtx stateKey