package logging

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

// DailyWriter writes log entries to <root>/<yyyy-mm-dd>/<name>. It keeps the
// file handle open for the active day and rotates on the first write after
// midnight, matching the directory layout consumed by the log viewer.
type DailyWriter struct {
	mu           sync.Mutex
	root         string
	name         string
	date         string
	file         *os.File
	retentionDay int
}

func NewDailyWriter(root, name string, retentionDay int) *DailyWriter {
	w := &DailyWriter{root: root, name: name, retentionDay: retentionDay}
	w.removeExpired()
	return w
}

func (w *DailyWriter) removeExpired() {
	if w.retentionDay <= 0 {
		return
	}
	entries, err := os.ReadDir(w.root)
	if err != nil {
		return
	}
	cutoff := time.Now().AddDate(0, 0, -w.retentionDay)
	for _, entry := range entries {
		if !entry.IsDir() {
			continue
		}
		date, err := time.Parse("2006-01-02", entry.Name())
		if err == nil && date.Before(cutoff) {
			_ = os.RemoveAll(filepath.Join(w.root, entry.Name()))
		}
	}
}

func (w *DailyWriter) Write(value []byte) (int, error) {
	w.mu.Lock()
	defer w.mu.Unlock()
	date := time.Now().Format("2006-01-02")
	if w.file == nil || w.date != date {
		if w.file != nil {
			_ = w.file.Close()
		}
		filePath := filepath.Join(w.root, date, filepath.Clean(w.name))
		directory := filepath.Dir(filePath)
		if err := os.MkdirAll(directory, 0o755); err != nil {
			return 0, err
		}
		file, err := os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644)
		if err != nil {
			return 0, err
		}
		w.file, w.date = file, date
	}
	return w.file.Write(value)
}

func (w *DailyWriter) Sync() error {
	w.mu.Lock()
	defer w.mu.Unlock()
	if w.file == nil {
		return nil
	}
	return w.file.Sync()
}

func (w *DailyWriter) Close() error {
	w.mu.Lock()
	defer w.mu.Unlock()
	if w.file == nil {
		return nil
	}
	err := w.file.Close()
	w.file = nil
	return err
}
