package storage

import (
	"bufio"
	"context"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/atlasos/calypso/internal/common/logger"
)

// ARCStats represents ZFS ARC (Adaptive Replacement Cache) statistics
type ARCStats struct {
	HitRatio     float64 `json:"hit_ratio"`     // Percentage of cache hits
	CacheUsage   float64 `json:"cache_usage"`   // Percentage of cache used
	CacheSize    int64   `json:"cache_size"`    // Current ARC size in bytes
	CacheMax     int64   `json:"cache_max"`     // Maximum ARC size in bytes
	Hits         int64   `json:"hits"`          // Total cache hits
	Misses       int64   `json:"misses"`        // Total cache misses
	DemandHits   int64   `json:"demand_hits"`   // Demand data/metadata hits
	PrefetchHits int64   `json:"prefetch_hits"` // Prefetch hits
	MRUHits      int64   `json:"mru_hits"`      // Most Recently Used hits
	MFUHits      int64   `json:"mfu_hits"`      // Most Frequently Used hits
	CollectedAt  string  `json:"collected_at"`  // Timestamp when stats were collected
}

// ARCService handles ZFS ARC statistics collection
type ARCService struct {
	logger *logger.Logger
}

// NewARCService creates a new ARC service
func NewARCService(log *logger.Logger) *ARCService {
	return &ARCService{
		logger: log,
	}
}

// GetARCStats reads and parses ARC statistics from /proc/spl/kstat/zfs/arcstats
func (s *ARCService) GetARCStats(ctx context.Context) (*ARCStats, error) {
	stats := &ARCStats{}

	// Read ARC stats file
	file, err := os.Open("/proc/spl/kstat/zfs/arcstats")
	if err != nil {
		return nil, fmt.Errorf("failed to open arcstats file: %w", err)
	}
	defer file.Close()

	// Parse the file
	scanner := bufio.NewScanner(file)
	arcData := make(map[string]int64)

	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())

		// Skip empty lines and header lines
		if line == "" || strings.HasPrefix(line, "name") || strings.HasPrefix(line, "9") {
			continue
		}

		// Parse lines like: "hits                            4    311154"
		fields := strings.Fields(line)
		if len(fields) >= 3 {
			key := fields[0]
			// The value is in the last field (field index 2)
			if value, err := strconv.ParseInt(fields[len(fields)-1], 10, 64); err == nil {
				arcData[key] = value
			}
		}
	}

	if err := scanner.Err(); err != nil {
		return nil, fmt.Errorf("failed to read arcstats file: %w", err)
	}

	// Extract key metrics
	stats.Hits = arcData["hits"]
	stats.Misses = arcData["misses"]
	stats.DemandHits = arcData["demand_data_hits"] + arcData["demand_metadata_hits"]
	stats.PrefetchHits = arcData["prefetch_data_hits"] + arcData["prefetch_metadata_hits"]
	stats.MRUHits = arcData["mru_hits"]
	stats.MFUHits = arcData["mfu_hits"]

	// Current ARC size (c) and max size (c_max)
	stats.CacheSize = arcData["c"]
	stats.CacheMax = arcData["c_max"]

	// Calculate hit ratio
	totalRequests := stats.Hits + stats.Misses
	if totalRequests > 0 {
		stats.HitRatio = float64(stats.Hits) / float64(totalRequests) * 100.0
	} else {
		stats.HitRatio = 0.0
	}

	// Calculate cache usage percentage
	if stats.CacheMax > 0 {
		stats.CacheUsage = float64(stats.CacheSize) / float64(stats.CacheMax) * 100.0
	} else {
		stats.CacheUsage = 0.0
	}

	// Set collection timestamp
	stats.CollectedAt = time.Now().Format(time.RFC3339)

	return stats, nil
}
