package main

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

// Logger writes structured logs to both stderr (dev) and a rotating file under the user
// config dir. Acceso seguro entre goroutines via sync.Mutex.
type Logger struct {
	mu      sync.Mutex
	file    *os.File
	slogger *slog.Logger
	logPath string
}

var globalLogger *Logger

func InitLogger() (*Logger, error) {
	cfgDir, err := os.UserConfigDir()
	if err != nil {
		cfgDir = filepath.Join(os.Getenv("HOME"), ".config")
	}
	dir := filepath.Join(cfgDir, "matrix_client_pc")
	if err := os.MkdirAll(dir, 0o700); err != nil {
		return nil, fmt.Errorf("mkdir log dir: %w", err)
	}
	logPath := filepath.Join(dir, "app.log")
	f, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o600)
	if err != nil {
		return nil, fmt.Errorf("open log file: %w", err)
	}

	multi := io.MultiWriter(os.Stderr, f)
	handler := slog.NewTextHandler(multi, &slog.HandlerOptions{
		Level: slog.LevelDebug,
	})
	l := &Logger{
		file:    f,
		slogger: slog.New(handler),
		logPath: logPath,
	}
	globalLogger = l
	l.Info("logger initialized", "path", logPath)
	return l, nil
}

func (l *Logger) Close() error {
	l.mu.Lock()
	defer l.mu.Unlock()
	if l.file != nil {
		_ = l.file.Sync()
		return l.file.Close()
	}
	return nil
}

func (l *Logger) Path() string { return l.logPath }

func (l *Logger) Debug(msg string, args ...any) { l.slogger.Debug(msg, args...) }
func (l *Logger) Info(msg string, args ...any)  { l.slogger.Info(msg, args...) }
func (l *Logger) Warn(msg string, args ...any)  { l.slogger.Warn(msg, args...) }
func (l *Logger) Error(msg string, args ...any) { l.slogger.Error(msg, args...) }

// Package-level helpers — no-op if InitLogger not called yet (defensive for tests).
func logDebug(msg string, args ...any) {
	if globalLogger != nil {
		globalLogger.Debug(msg, args...)
	}
}
func logInfo(msg string, args ...any) {
	if globalLogger != nil {
		globalLogger.Info(msg, args...)
	}
}
func logWarn(msg string, args ...any) {
	if globalLogger != nil {
		globalLogger.Warn(msg, args...)
	}
}
func logError(msg string, args ...any) {
	if globalLogger != nil {
		globalLogger.Error(msg, args...)
	}
}

// TailLog returns the last N lines of the log file.
func TailLog(n int) ([]string, error) {
	if globalLogger == nil {
		return nil, fmt.Errorf("logger not initialized")
	}
	b, err := os.ReadFile(globalLogger.logPath)
	if err != nil {
		return nil, fmt.Errorf("read log: %w", err)
	}
	// Split + return last N.
	lines := splitLines(string(b))
	if len(lines) <= n {
		return lines, nil
	}
	return lines[len(lines)-n:], nil
}

func splitLines(s string) []string {
	out := []string{}
	cur := ""
	for _, r := range s {
		if r == '\n' {
			out = append(out, cur)
			cur = ""
			continue
		}
		cur += string(r)
	}
	if cur != "" {
		out = append(out, cur)
	}
	return out
}
