package log

import (
	"fmt"
	"io"
	"log"
	"os"
	"sync"
)

type Level int

const (
	PanicLevel Level = iota
	FatalLevel
	ErrorLevel
	WarnLevel
	InfoLevel
	DebugLevel
	TraceLevel
)

var AllLoggers = []Level{InfoLevel}

type Logger struct {
	name   string
	level  Level
	output io.Writer
	mu     sync.Mutex
}

type TextFormatter struct {
	FullTimestamp   bool
	TimestampFormat string
}

var loggers = make(map[string]*Logger)
var loggersMu sync.Mutex

func GetLogger(name string) *Logger {
	loggersMu.Lock()
	defer loggersMu.Unlock()

	if l, ok := loggers[name]; ok {
		return l
	}

	logger := &Logger{
		name:   name,
		level:  InfoLevel,
		output: os.Stderr,
	}
	loggers[name] = logger
	return logger
}

func ParseLevel(s string) (Level, error) {
	switch s {
	case "panic":
		return PanicLevel, nil
	case "fatal":
		return FatalLevel, nil
	case "error":
		return ErrorLevel, nil
	case "warn", "warning":
		return WarnLevel, nil
	case "info":
		return InfoLevel, nil
	case "debug":
		return DebugLevel, nil
	case "trace":
		return TraceLevel, nil
	default:
		return InfoLevel, fmt.Errorf("unknown level: %s", s)
	}
}

func SetLevel(levels []Level, level Level) {
	loggersMu.Lock()
	defer loggersMu.Unlock()
	for _, l := range loggers {
		l.level = level
	}
}

func SetFormatter(levels []Level, formatter *TextFormatter) {
	// No-op for stub
}

func SetOutput(levels []Level, output io.Writer) {
	loggersMu.Lock()
	defer loggersMu.Unlock()
	for _, l := range loggers {
		l.output = output
	}
}

func NewLockOutput(w io.Writer) io.Writer {
	return w
}

type ErrorStackHook struct {
	enabled bool
}

func NewErrorStackHook(enabled bool) *ErrorStackHook {
	return &ErrorStackHook{enabled: enabled}
}

func (h *ErrorStackHook) Levels() []Level {
	return AllLoggers
}

func (h *ErrorStackHook) Fire(entry *struct{}) error {
	return nil
}

func AddHook(levels []Level, hook interface{}) {
	// No-op for stub
}

func (l *Logger) log(level, format string, args ...interface{}) {
	l.mu.Lock()
	defer l.mu.Unlock()
	msg := fmt.Sprintf("[%s] [%s] %s", l.name, level, fmt.Sprintf(format, args...))
	log.Println(msg)
}

func (l *Logger) Infof(format string, args ...interface{}) {
	l.log("INFO", format, args...)
}

func (l *Logger) Debugf(format string, args ...interface{}) {
	l.log("DEBUG", format, args...)
}

func (l *Logger) Warnf(format string, args ...interface{}) {
	l.log("WARN", format, args...)
}

func (l *Logger) Errorf(format string, args ...interface{}) {
	l.log("ERROR", format, args...)
}

func (l *Logger) Fatalf(format string, args ...interface{}) {
	l.log("FATAL", format, args...)
	os.Exit(1)
}

func (l *Logger) Fatal(args ...interface{}) {
	l.log("FATAL", "%v", args)
	os.Exit(1)
}

func (l *Logger) Fatalln(args ...interface{}) {
	l.log("FATAL", "%v", args)
	os.Exit(1)
}

func (l *Logger) Info(args ...interface{}) {
	l.log("INFO", "%v", args)
}

func (l *Logger) Infoln(args ...interface{}) {
	l.log("INFO", "%v", args)
}

func (l *Logger) Error(args ...interface{}) {
	l.log("ERROR", "%v", args)
}

func (l *Logger) Errorln(args ...interface{}) {
	l.log("ERROR", "%v", args)
}

func (l *Logger) Warn(args ...interface{}) {
	l.log("WARN", "%v", args)
}

func (l *Logger) Warnln(args ...interface{}) {
	l.log("WARN", "%v", args)
}

func (l *Logger) Debug(args ...interface{}) {
	l.log("DEBUG", "%v", args)
}

func (l *Logger) Debugln(args ...interface{}) {
	l.log("DEBUG", "%v", args)
}

func (l *Logger) WithError(err error) *Logger {
	return l
}

func (l *Logger) WithField(key string, value interface{}) *Logger {
	return l
}

func Infof(format string, args ...interface{}) {
	log.Printf("[INFO] "+format, args...)
}

func Fatalf(format string, args ...interface{}) {
	log.Printf("[FATAL] "+format, args...)
	os.Exit(1)
}

func Fatal(args ...interface{}) {
	log.Printf("[FATAL] %v", args)
	os.Exit(1)
}
