package wiiudownloader

import (
	"io"
	"log"
	"os"
)

type LogLevel int

const (
	Info LogLevel = iota
	Warning
	Error
	Fatal
)

var logLevelStrings = map[LogLevel]string{
	Info:    "[Info]",
	Warning: "[Warning]",
	Error:   "[Error]",
	Fatal:   "[Fatal]",
}

type Logger struct {
	logFile *os.File
	logger  *log.Logger
}

func NewLogger(logFilePath string) (*Logger, error) {
	var logFile *os.File
	var err error

	// If logFilePath is empty, log only to stdout
	if logFilePath == "" {
		return &Logger{
			logger: log.New(os.Stdout, "", log.Ldate|log.Ltime),
		}, nil
	}

	// Open the log file for writing, truncating it if it exists
	logFile, err = os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o666)
	if err != nil {
		// If unable to open the log file, log the error to stdout
		log.New(os.Stdout, "", log.Ldate|log.Ltime).Printf("[Error] Unable to open log file: %v\n", err)
		return &Logger{
			logger: log.New(os.Stdout, "", log.Ldate|log.Ltime),
		}, nil
	}

	// Create the logger that writes to both stdout and the file
	logger := log.New(io.MultiWriter(os.Stdout, logFile), "", log.Ldate|log.Ltime)

	return &Logger{
		logFile: logFile,
		logger:  logger,
	}, nil
}

func (l *Logger) log(level LogLevel, format string, v ...interface{}) {
	if prefix, ok := logLevelStrings[level]; ok {
		l.logger.Printf(prefix+" "+format, v...)
	}
}

func (l *Logger) Info(format string, v ...interface{}) {
	l.log(Info, format, v...)
}

func (l *Logger) Warning(format string, v ...interface{}) {
	l.log(Warning, format, v...)
}

func (l *Logger) Error(format string, v ...interface{}) {
	l.log(Error, format, v...)
}

func (l *Logger) Fatal(format string, v ...interface{}) {
	l.log(Fatal, format, v...)
	os.Exit(1)
}