// Package debug provides debug logging utilities for agnt.
package debug

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

var (
	// enabled controls whether debug logging is active
	enabled atomic.Bool

	// logFile is the optional file to write debug logs to
	logFile     *os.File
	logFileMu   sync.Mutex
	logFilePath string

	// logger is the debug logger instance
	logger *log.Logger
)

func init() {
	// Check environment variable on startup
	if os.Getenv("AGNT_DEBUG") != "" {
		Enable()
	}

	// Initialize logger to stderr by default
	logger = log.New(os.Stderr, "", log.LstdFlags)
}

// Enable turns on debug logging.
func Enable() {
	enabled.Store(true)
}

// Disable turns off debug logging.
func Disable() {
	enabled.Store(false)
}

// IsEnabled returns whether debug logging is enabled.
func IsEnabled() bool {
	return enabled.Load()
}

// SetLogFile sets an optional file to write debug logs to.
// If path is empty, logs go to stderr only.
// The file is created/appended to in the user's cache directory.
func SetLogFile(name string) error {
	logFileMu.Lock()
	defer logFileMu.Unlock()

	// Close existing file if open
	if logFile != nil {
		logFile.Close()
		logFile = nil
	}

	if name == "" {
		logger.SetOutput(os.Stderr)
		logFilePath = ""
		return nil
	}

	// Create log file in cache directory
	cacheDir, err := os.UserCacheDir()
	if err != nil {
		cacheDir = os.TempDir()
	}

	logDir := filepath.Join(cacheDir, "agnt", "logs")
	if err := os.MkdirAll(logDir, 0755); err != nil {
		return fmt.Errorf("failed to create log directory: %w", err)
	}

	logFilePath = filepath.Join(logDir, name)
	f, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		return fmt.Errorf("failed to open log file: %w", err)
	}

	logFile = f

	// Write to file only (stderr corrupts PTY/MCP output)
	logger.SetOutput(f)

	return nil
}

// GetLogFilePath returns the current log file path, or empty if not set.
func GetLogFilePath() string {
	logFileMu.Lock()
	defer logFileMu.Unlock()
	return logFilePath
}

// Close closes the log file if open.
func Close() {
	logFileMu.Lock()
	defer logFileMu.Unlock()

	if logFile != nil {
		logFile.Close()
		logFile = nil
	}
}

// Log logs a debug message if debug mode is enabled.
// Format: [DEBUG] [component] message
func Log(component, format string, args ...interface{}) {
	if !enabled.Load() {
		return
	}

	msg := fmt.Sprintf(format, args...)
	logger.Printf("[DEBUG] [%s] %s", component, msg)
}

// LogWithTimestamp logs a debug message with a high-precision timestamp.
func LogWithTimestamp(component, format string, args ...interface{}) {
	if !enabled.Load() {
		return
	}

	msg := fmt.Sprintf(format, args...)
	ts := time.Now().Format("15:04:05.000")
	logger.Printf("[DEBUG] [%s] [%s] %s", ts, component, msg)
}

// Error logs an error message (always logged, regardless of debug mode).
func Error(component, format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)
	logger.Printf("[ERROR] [%s] %s", component, msg)
}

// Warn logs a warning message (always logged, regardless of debug mode).
func Warn(component, format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)
	logger.Printf("[WARN] [%s] %s", component, msg)
}

// Info logs an info message (always logged, regardless of debug mode).
func Info(component, format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)
	logger.Printf("[INFO] [%s] %s", component, msg)
}

// Trace logs a detailed trace message (only when debug is enabled).
// Use for very verbose logging like individual function calls.
func Trace(component, format string, args ...interface{}) {
	if !enabled.Load() {
		return
	}

	msg := fmt.Sprintf(format, args...)
	ts := time.Now().Format("15:04:05.000000")
	logger.Printf("[TRACE] [%s] [%s] %s", ts, component, msg)
}

// DumpToFile writes all buffered logs to a file for debugging.
// Returns the file path.
func DumpToFile(prefix string) (string, error) {
	cacheDir, err := os.UserCacheDir()
	if err != nil {
		cacheDir = os.TempDir()
	}

	logDir := filepath.Join(cacheDir, "agnt", "logs")
	if err := os.MkdirAll(logDir, 0755); err != nil {
		return "", fmt.Errorf("failed to create log directory: %w", err)
	}

	filename := fmt.Sprintf("%s-%s.log", prefix, time.Now().Format("20060102-150405"))
	path := filepath.Join(logDir, filename)

	return path, nil
}
