package log

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"sync"
	"time"
)

var (
	logger       *Logger
	once         sync.Once
	logMutex     sync.Mutex
	outputChan   chan string
	verboseMode  bool
	debugMode    bool
	alwaysStderr bool
)

type Logger struct {
	file     *os.File
	filePath string
	enabled  bool
}

type LogLevel int

const (
	LevelDebug LogLevel = iota
	LevelInfo
	LevelWarn
	LevelError
)

func Init() {
	once.Do(func() {
		debugPrintf("=== Log Init Started ===")

		homeDir, err := os.UserHomeDir()
		if err != nil {
			debugPrintf("ERROR: os.UserHomeDir() failed: %v", err)
			fmt.Fprintf(os.Stderr, "[ERROR] Failed to get user home directory: %v\n", err)
			homeDir = "."
		} else {
			debugPrintf("User home directory: %s", homeDir)
		}

		var logDir string
		var logPath string

		// On Windows, use portable_config in detected MPV directory
		if runtime.GOOS == "windows" {
			logDir = filepath.Join(homeDir, "mpv", "portable_config")
			// Check if legacy path exists
			if _, err := os.Stat(logDir); os.IsNotExist(err) {
				// Try AppData path for fresh installs
				appData := os.Getenv("APPDATA")
				if appData != "" {
					appDataLogDir := filepath.Join(appData, "mpv", "portable_config")
					// Use AppData path if legacy doesn't exist
					logDir = appDataLogDir
				}
			}
		} else {
			logDir = filepath.Join(homeDir, ".config", "mpv")
		}

		debugPrintf("Attempting to create log directory: %s", logDir)

		// Try to create log directory
		if err := os.MkdirAll(logDir, 0755); err != nil {
			debugPrintf("ERROR: os.MkdirAll(%s) failed: %v", logDir, err)
			fmt.Fprintf(os.Stderr, "[ERROR] Failed to create log directory '%s': %v\n", logDir, err)

			// Try fallback to current directory
			logDir = "."
			debugPrintf("Falling back to current directory: %s", logDir)
			fmt.Fprintf(os.Stderr, "[INFO] Falling back to current directory for logs\n")

			if err := os.MkdirAll(logDir, 0755); err != nil {
				debugPrintf("ERROR: Fallback os.MkdirAll() also failed: %v", err)
				fmt.Fprintf(os.Stderr, "[ERROR] Failed to create fallback log directory: %v\n", err)
				return
			}
		} else {
			debugPrintf("Successfully created log directory")
		}

		logPath = filepath.Join(logDir, "mpv-manager.log")
		debugPrintf("Log file path: %s", logPath)

		file, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
		if err != nil {
			debugPrintf("ERROR: os.OpenFile(%s) failed: %v", logPath, err)
			fmt.Fprintf(os.Stderr, "[ERROR] Failed to create log file '%s': %v\n", logPath, err)
			return
		} else {
			debugPrintf("Successfully opened log file")
		}

		logger = &Logger{
			file:     file,
			filePath: logPath,
			enabled:  true,
		}

		outputChan = make(chan string, 100)

		go func() {
			for msg := range outputChan {
				if logger.enabled && logger.file != nil {
					logger.file.WriteString(msg)
				}
			}
		}()

		Write("=== MPV.Rocks Installer Log Started ===")
		Write(fmt.Sprintf("Timestamp: %s", time.Now().Format(time.RFC3339)))
		debugPrintf("=== Log Init Complete ===")
	})
}

func SetVerboseMode(enabled bool) {
	verboseMode = enabled
	if enabled {
		alwaysStderr = true
	}
}

func SetDebugMode(enabled bool) {
	debugMode = enabled
	if enabled {
		alwaysStderr = true
	}
}

func debugPrintf(format string, args ...interface{}) {
	if verboseMode || debugMode || alwaysStderr {
		msg := fmt.Sprintf(format, args...)
		fmt.Fprintf(os.Stderr, "[DEBUG] %s\n", msg)
	}
}

func Close() {
	if logger != nil {
		Write("=== MPV.Rocks Installer Log Ended ===")
		Flush()
		logMutex.Lock()
		if logger.file != nil {
			logger.file.Sync()
			logger.file.Close()
		}
		logger.enabled = false
		logMutex.Unlock()

		if outputChan != nil {
			close(outputChan)
		}
	}
}

func Flush() {
	if outputChan != nil {
		for len(outputChan) > 0 {
			time.Sleep(10 * time.Millisecond)
		}
		time.Sleep(50 * time.Millisecond)
	}
}

func Write(msg string) {
	if logger == nil || !logger.enabled {
		return
	}
	timestamp := time.Now().Format("2006-01-02 15:04:05")
	formatted := fmt.Sprintf("[%s] %s\n", timestamp, msg)
	select {
	case outputChan <- formatted:
	default:
	}
}

func Info(msg string) {
	Write(fmt.Sprintf("[INFO] %s", msg))
}

func Debug(msg string) {
	Write(fmt.Sprintf("[DEBUG] %s", msg))
}

func Warn(msg string) {
	Write(fmt.Sprintf("[WARN] %s", msg))
}

func Error(msg string) {
	Write(fmt.Sprintf("[ERROR] %s", msg))
}

func Command(cmd string) {
	Write(fmt.Sprintf("[COMMAND] %s", cmd))
}

func Output(output string) {
	Write(fmt.Sprintf("[OUTPUT] %s", output))
}

func ErrorOutput(output string) {
	Write(fmt.Sprintf("[ERROR-OUTPUT] %s", output))
}

func Separator(msg string) {
	Write(fmt.Sprintf("--- %s ---", msg))
}

func GetFilePath() string {
	if logger != nil {
		return logger.filePath
	}
	return ""
}
