// package log_buf -- потокобезопасный буфер лога
package log_buf

import (
	"fmt"

	"gitp78su.ipnodns.ru/svi/kern/kc/log_buf/log_msg"
	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
)

// logBuf -- потокобезопасный буфер лога
type logBuf struct {
	chGetIn  chan int
	chGetOut chan ILogMsg

	chDebugIn  chan tMsg
	chDebugOut chan int

	chInfoIn  chan tMsg
	chInfoOut chan int

	chWarnIn  chan tMsg
	chWarnOut chan int

	chErrorIn chan tMsg

	lst []ILogMsg

	chGetErrIn  chan int
	chGetErrOut chan ILogMsg
	lstErr      []ILogMsg

	chSizeIn  chan int
	chSizeOut chan int
}

// NewLogBuf -- возвращает новый потокобезопасный буфер лога
func NewLogBuf() ILogBuf {
	sf := &logBuf{
		chGetIn:  make(chan int, 2),
		chGetOut: make(chan ILogMsg, 2),

		chDebugIn:  make(chan tMsg, 2),
		chDebugOut: make(chan int, 2),

		chInfoIn:  make(chan tMsg, 2),
		chInfoOut: make(chan int, 2),

		chWarnIn:  make(chan tMsg, 2),
		chWarnOut: make(chan int, 2),

		chErrorIn: make(chan tMsg, 2),

		lst: []ILogMsg{},

		chGetErrIn:  make(chan int, 2),
		chGetErrOut: make(chan ILogMsg, 2),
		lstErr:      []ILogMsg{},

		chSizeIn:  make(chan int, 2),
		chSizeOut: make(chan int, 2),
	}
	go sf.run()
	return sf
}

// GetErr -- возвращает сообщение ошибки по номеру
func (sf *logBuf) GetErr(num int) ILogMsg {
	sf.chGetErrIn <- num
	return <-sf.chGetErrOut
}

// Get -- возвращает сообщение по номеру
func (sf *logBuf) Get(num int) ILogMsg {
	sf.chGetIn <- num
	return <-sf.chGetOut
}

type tMsg struct {
	text string
	args []any
}

// Debug -- сообщение отладки
func (sf *logBuf) Debug(fMsg string, args ...any) {
	msg := tMsg{
		text: fMsg,
		args: args,
	}
	sf.chDebugIn <- msg
	<-sf.chDebugOut
}

// Info -- информационные сообщения
func (sf *logBuf) Info(fMsg string, args ...any) {
	msg := tMsg{
		text: fMsg,
		args: args,
	}
	sf.chInfoIn <- msg
	<-sf.chInfoOut
}

// Warn -- предупреждающие сообщения
func (sf *logBuf) Warn(fMsg string, args ...any) {
	msg := tMsg{
		text: fMsg,
		args: args,
	}
	sf.chWarnIn <- msg
	<-sf.chWarnOut
}

// Err -- сообщения об ошибках
func (sf *logBuf) Err(fMsg string, args ...any) {
	msg := tMsg{
		text: fMsg,
		args: args,
	}
	sf.chErrorIn <- msg
}

// Size -- возвращает размер буфера
func (sf *logBuf) Size() int {
	sf.chSizeIn <- 1
	return <-sf.chSizeOut
}

func (sf *logBuf) run() {
	for {
		select {
		case num := <-sf.chGetErrIn:
			sf.chGetErrOut <- sf.getErr(num)
		case num := <-sf.chGetIn:
			sf.chGetOut <- sf.get(num)
		case msg := <-sf.chDebugIn:
			sf.debug(msg)
			sf.chDebugOut <- 1
		case msg := <-sf.chInfoIn:
			sf.info(msg)
			sf.chInfoOut <- 1
		case msg := <-sf.chWarnIn:
			sf.warn(msg)
			sf.chWarnOut <- 1
		case msg := <-sf.chErrorIn:
			sf.err(msg)
		case <-sf.chSizeIn:
			sf.chSizeOut <- len(sf.lst)
		}
	}
}

// Возвращает сообщение ошибки по номеру
func (sf *logBuf) getErr(num int) ILogMsg {
	if len(sf.lstErr) == 0 {
		return log_msg.NewLogMsg(log_msg.DEBUG, "not error msg")
	}
	if num >= len(sf.lstErr) {
		return sf.lstErr[len(sf.lstErr)-1]
	}
	if num <= 0 {
		return sf.lstErr[0]
	}
	return sf.lstErr[num]
}

// возвращает сообщение по номеру
func (sf *logBuf) get(num int) ILogMsg {
	if len(sf.lst) == 0 {
		return log_msg.NewLogMsg(log_msg.DEBUG, "*no msg*")
	}
	if num >= len(sf.lst) {
		return log_msg.NewLogMsg(log_msg.DEBUG, "*no msg*")
	}
	if num <= 0 {
		return log_msg.NewLogMsg(log_msg.DEBUG, "*no msg*")
	}
	return sf.lst[num]
}

// сообщение отладки
func (sf *logBuf) debug(msg tMsg) {
	strMsg := fmt.Sprintf(msg.text, msg.args...)
	_msg := log_msg.NewLogMsg(log_msg.DEBUG, strMsg)
	sf.lst = append(sf.lst, _msg)
	sf.checkLen()
}

// информационные сообщения
func (sf *logBuf) info(msg tMsg) {
	strMsg := fmt.Sprintf(msg.text, msg.args...)
	_msg := log_msg.NewLogMsg(log_msg.INFO, strMsg)
	sf.lst = append(sf.lst, _msg)
	sf.checkLen()
}

// предупреждающие сообщения
func (sf *logBuf) warn(msg tMsg) {
	strMsg := fmt.Sprintf(msg.text, msg.args...)
	_msg := log_msg.NewLogMsg(log_msg.WARN, strMsg)
	sf.lst = append(sf.lst, _msg)
	sf.checkLen()
}

// сообщения об ошибках
func (sf *logBuf) err(msg tMsg) {
	strMsg := fmt.Sprintf(msg.text, msg.args...)
	_msg := log_msg.NewLogMsg(log_msg.ERROR, strMsg)
	sf.lst = append(sf.lst, _msg)
	sf.lstErr = append(sf.lstErr, _msg)
	sf.checkLen()
	sf.checkLenErr()
}

// Проверяет длину общую лога
func (sf *logBuf) checkLen() {
	for len(sf.lst) > 100 {
		sf.lst = sf.lst[1:]
	}
}

// Проверяет длину лога ошибок
func (sf *logBuf) checkLenErr() {
	for len(sf.lstErr) > 100 {
		sf.lstErr = sf.lstErr[1:]
	}
}
