package logger

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"sync"
	"time"
)

// Log levels
const (
	LevelInfo  = "INFO"
	LevelWarn  = "WARNING"
	LevelError = "ERROR"
	LevelDebug = "DEBUG"
)

// Logger provides dual-output logging to stdout and a file
type Logger struct {
	infoLog  *log.Logger
	warnLog  *log.Logger
	errorLog *log.Logger
	debugLog *log.Logger
	debug    bool
	mu       sync.Mutex
}

var defaultLogger *Logger

func init() {
	defaultLogger = NewLogger(false, "")
}

// SetDefault sets the default logger instance
func SetDefault(l *Logger) {
	defaultLogger = l
}

// Default returns the current default logger
func Default() *Logger {
	return defaultLogger
}

// NewLogger creates a new dual-output logger.
// If logPath is empty, only stdout is used.
func NewLogger(debug bool, logPath string) *Logger {
	flags := log.Ldate | log.Ltime | log.Lmicroseconds

	var infoWriter, warnWriter, errorWriter, debugWriter io.Writer

	if logPath != "" {
		// Ensure directory exists
		dir := filepath.Dir(logPath)
		if err := os.MkdirAll(dir, 0755); err == nil {
			file, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
			if err == nil {
				// Multi-writer: stdout + file
				infoWriter = io.MultiWriter(os.Stdout, file)
				warnWriter = io.MultiWriter(os.Stdout, file)
				errorWriter = io.MultiWriter(os.Stderr, file)
				debugWriter = io.MultiWriter(os.Stdout, file)

				fmt.Fprintf(os.Stdout, "%s [%s] LOGGER: log file opened: %s\n",
					time.Now().Format("2006/01/02 15:04:05.000"), LevelInfo, logPath)
			} else {
				fmt.Fprintf(os.Stderr, "%s [%s] LOGGER: failed to open log file %s: %v, using stdout only\n",
					time.Now().Format("2006/01/02 15:04:05.000"), LevelWarn, logPath, err)
				infoWriter = os.Stdout
				warnWriter = os.Stdout
				errorWriter = os.Stderr
				debugWriter = os.Stdout
			}
		} else {
			fmt.Fprintf(os.Stderr, "%s [%s] LOGGER: failed to create log dir %s: %v, using stdout only\n",
				time.Now().Format("2006/01/02 15:04:05.000"), LevelWarn, dir, err)
			infoWriter = os.Stdout
			warnWriter = os.Stdout
			errorWriter = os.Stderr
			debugWriter = os.Stdout
		}
	} else {
		infoWriter = os.Stdout
		warnWriter = os.Stdout
		errorWriter = os.Stderr
		debugWriter = os.Stdout
	}

	return &Logger{
		infoLog:  log.New(infoWriter, "", flags),
		warnLog:  log.New(warnWriter, "", flags),
		errorLog: log.New(errorWriter, "", flags),
		debugLog: log.New(debugWriter, "", flags),
		debug:    debug,
	}
}

// Info logs an INFO message
func (l *Logger) Info(format string, args ...interface{}) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.infoLog.Printf("[%s] %s", LevelInfo, fmt.Sprintf(format, args...))
}

// Warn logs a WARNING message
func (l *Logger) Warn(format string, args ...interface{}) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.warnLog.Printf("[%s] %s", LevelWarn, fmt.Sprintf(format, args...))
}

// Error logs an ERROR message
func (l *Logger) Error(format string, args ...interface{}) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.errorLog.Printf("[%s] %s", LevelError, fmt.Sprintf(format, args...))
}

// Debug logs a DEBUG message (only if debug mode is enabled)
func (l *Logger) Debug(format string, args ...interface{}) {
	if !l.debug {
		return
	}
	l.mu.Lock()
	defer l.mu.Unlock()
	l.debugLog.Printf("[%s] %s", LevelDebug, fmt.Sprintf(format, args...))
}

// Info logs an INFO message using the default logger
func Info(format string, args ...interface{}) {
	defaultLogger.Info(format, args...)
}

// Warn logs a WARNING message using the default logger
func Warn(format string, args ...interface{}) {
	defaultLogger.Warn(format, args...)
}

// Error logs an ERROR message using the default logger
func Error(format string, args ...interface{}) {
	defaultLogger.Error(format, args...)
}

// Debug logs a DEBUG message using the default logger
func Debug(format string, args ...interface{}) {
	defaultLogger.Debug(format, args...)
}

// SetDebug enables or disables debug logging
func (l *Logger) SetDebug(debug bool) {
	l.debug = debug
}