package log

import (
	"os"
	"strings"
	"sync"

	"github.com/charmbracelet/lipgloss"
	cblog "github.com/charmbracelet/log"
)

// Logger embeds the Charm Logger and adds Printf/Fatalf
type Logger struct{ *cblog.Logger }

// Printf routes goose/info-style logs through Infof.
func (l *Logger) Printf(format string, v ...any) { l.Infof(format, v...) }

// Fatalf keeps goose’s contract of exiting the program.
func (l *Logger) Fatalf(format string, v ...any) { l.Logger.Fatalf(format, v...) }

var (
	logger     *Logger
	initLogger sync.Once
)

func parseLogLevel(level string) cblog.Level {
	switch strings.ToLower(level) {
	case "debug":
		return cblog.DebugLevel
	case "info":
		return cblog.InfoLevel
	case "warn", "warning":
		return cblog.WarnLevel
	case "error":
		return cblog.ErrorLevel
	case "fatal":
		return cblog.FatalLevel
	default:
		return cblog.InfoLevel
	}
}

func GetQtLoggingRules() string {
	level := os.Getenv("DMS_LOG_LEVEL")
	if level == "" {
		level = "info"
	}

	var rules []string
	switch strings.ToLower(level) {
	case "fatal":
		rules = []string{"*.debug=false", "*.info=false", "*.warning=false", "*.critical=false"}
	case "error":
		rules = []string{"*.debug=false", "*.info=false", "*.warning=false"}
	case "warn", "warning":
		rules = []string{"*.debug=false", "*.info=false"}
	case "info":
		rules = []string{"*.debug=false"}
	case "debug":
		return ""
	default:
		rules = []string{"*.debug=false"}
	}

	return strings.Join(rules, ";")
}

// GetLogger returns a logger instance
func GetLogger() *Logger {
	initLogger.Do(func() {
		styles := cblog.DefaultStyles()
		// Attempt to match the colors used by qml/quickshell logs
		styles.Levels[cblog.FatalLevel] = lipgloss.NewStyle().
			SetString(" FATAL").
			Foreground(lipgloss.Color("1"))
		styles.Levels[cblog.ErrorLevel] = lipgloss.NewStyle().
			SetString(" ERROR").
			Foreground(lipgloss.Color("9"))
		styles.Levels[cblog.WarnLevel] = lipgloss.NewStyle().
			SetString("  WARN").
			Foreground(lipgloss.Color("3"))
		styles.Levels[cblog.InfoLevel] = lipgloss.NewStyle().
			SetString("  INFO").
			Foreground(lipgloss.Color("2"))
		styles.Levels[cblog.DebugLevel] = lipgloss.NewStyle().
			SetString(" DEBUG").
			Foreground(lipgloss.Color("4"))

		base := cblog.New(os.Stderr)
		base.SetStyles(styles)
		base.SetReportTimestamp(false)

		level := cblog.InfoLevel
		if envLevel := os.Getenv("DMS_LOG_LEVEL"); envLevel != "" {
			level = parseLogLevel(envLevel)
		}
		base.SetLevel(level)
		base.SetPrefix(" go")

		logger = &Logger{base}
	})
	return logger
}

// * Convenience wrappers

func Debug(msg any, keyvals ...any)  { GetLogger().Debug(msg, keyvals...) }
func Debugf(format string, v ...any) { GetLogger().Debugf(format, v...) }
func Info(msg any, keyvals ...any)   { GetLogger().Info(msg, keyvals...) }
func Infof(format string, v ...any)  { GetLogger().Infof(format, v...) }
func Warn(msg any, keyvals ...any)   { GetLogger().Warn(msg, keyvals...) }
func Warnf(format string, v ...any)  { GetLogger().Warnf(format, v...) }
func Error(msg any, keyvals ...any)  { GetLogger().Error(msg, keyvals...) }
func Errorf(format string, v ...any) { GetLogger().Errorf(format, v...) }
func Fatal(msg any, keyvals ...any)  { GetLogger().Fatal(msg, keyvals...) }
func Fatalf(format string, v ...any) { GetLogger().Fatalf(format, v...) }
