package loggers

import (
	"fmt"
	"io"
	"os"
	"time"

	"github.com/haydenhargreaves/Potion/internal/infrastructure/logging"
)

type ConsoleLogger struct {
	writer io.Writer
	filter logging.LogLevel
}

var _ logging.Logger = (*ConsoleLogger)(nil)

// NewConsoleLogger creates a new logger which writes directly to standard out (stdout).
func NewConsoleLogger(filter logging.LogLevel) logging.Logger {
	return &ConsoleLogger{
		writer: os.Stdout,
		filter: filter,
	}
}

// formatLevelString converts a log level string (level) into a new, formatted output string.
// This also includes color, if the shell supports it. Otherwise, the rendering may appear odd.
func formatLevelString(level logging.LogLevel) string {
	switch level {
	case logging.LogLevelTrace:
		return fmt.Sprintf("%s[%s]%s", logging.BgMagenta, level, logging.Reset)
	case logging.LogLevelDebug:
		return fmt.Sprintf("%s[%s]%s", logging.BgBlue, level, logging.Reset)
	case logging.LogLevelInfo:
		return fmt.Sprintf("%s[%s]%s", logging.BgGreen, level, logging.Reset)
	case logging.LogLevelWarning:
		return fmt.Sprintf("%s[%s]%s", logging.BgYellow, level, logging.Reset)
	case logging.LogLevelError:
		return fmt.Sprintf("%s[%s]%s", logging.BgRed, level, logging.Reset)
	case logging.LogLevelFatal:
		return fmt.Sprintf("%s[%s]%s", logging.BgRed, level, logging.Reset)
	}
	return fmt.Sprintf("[%s]", level)
}

// Log implements the interface.
func (l *ConsoleLogger) Log(level logging.LogLevel, format string, v ...any) {
	// level is too low, do not log
	if !l.filter.MatchFilter(level) {
		return
	}

	timestamp := time.Now().UTC().Format("01/02/2006 - 15:04:05")
	levelStr := formatLevelString(level)
	fullFormat := fmt.Sprintf("%-18s %s | %s\n", levelStr, timestamp, format)
	bytes := fmt.Appendf(nil, fullFormat, v...)
	l.writer.Write(bytes)
}
