// Package log реализует ASCII-логгер метрик с ротацией по дням.
// Формат: "2026-06-25T10:00:00Z pbx-01 calls=42 load=0.85 idle_cpu=35 fail=0.5 score=73"
package log

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/pulse-lets-go/internal/models"
)

// Logger — потокобезопасный логгер метрик в ASCII-файл с дневной ротацией.
type Logger struct {
	mu    sync.Mutex
	dir   string
	file  *os.File
	today string // YYYY-MM-DD последнего открытого файла
}

// NewLogger создаёт логгер, записывающий в dataDir/.
// Файлы именуются как metrics.YYYY-MM-DD.log.
func NewLogger(dataDir string) (*Logger, error) {
	if err := os.MkdirAll(dataDir, 0750); err != nil {
		return nil, fmt.Errorf("создание data/: %w", err)
	}
	l := &Logger{dir: dataDir}
	if err := l.ensureFile(); err != nil {
		return nil, err
	}
	return l, nil
}

// Log записывает снапшот метрик ноды в лог-файл.
func (l *Logger) Log(ns *models.NodeState) {
	l.mu.Lock()
	defer l.mu.Unlock()

	if err := l.ensureFile(); err != nil {
		return // тихая ошибка — не блокируем метрики из-за логгера
	}

	line := l.formatLine(ns)
	l.file.WriteString(line + "\n")
}

// formatLine форматирует строку лога.
func (l *Logger) formatLine(ns *models.NodeState) string {
	t := time.Unix(ns.TS, 0).UTC().Format(time.RFC3339)
	return fmt.Sprintf("%s %s calls=%d load=%.2f idle_cpu=%.1f fail=%.1f score=%.1f disabled=%t",
		t, ns.NodeID, ns.ActiveCalls, ns.LoadAvg, ns.IdleCPU, ns.CallFailureRate, ns.Score, ns.Disabled)
}

// Close закрывает файл лога.
func (l *Logger) Close() error {
	l.mu.Lock()
	defer l.mu.Unlock()
	if l.file != nil {
		return l.file.Close()
	}
	return nil
}

// ensureFile открывает файл на текущий день, создавая новый, если день сменился.
// Вызывающий держит mu.
func (l *Logger) ensureFile() error {
	today := time.Now().UTC().Format("2006-01-02")
	if l.file != nil && l.today == today {
		return nil
	}

	if l.file != nil {
		l.file.Close()
	}

	path := filepath.Join(l.dir, "metrics."+today+".log")
	f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0640)
	if err != nil {
		return fmt.Errorf("открытие лог-файла %s: %w", path, err)
	}

	l.file = f
	l.today = today
	return nil
}

// TrimPrefix обрезает "metrics." и ".log" из имени файла (для API истории).
func TrimPrefix(filename string) string {
	return strings.TrimPrefix(strings.TrimSuffix(filename, ".log"), "metrics.")
}
