package filesystem

import (
	"context"
	"encoding/json"
	"log/slog"
	"os"
	"strings"
	"time"
)

func (c *CachedClient) Stat(path string) (info os.FileInfo, err error) {
	key := keyStat + path
	ctx := context.Background()

	// Try cache
	val, err := c.cache.Do(ctx, c.cache.B().Get().Key(key).Build()).ToString()
	if err == nil && val != "" {
		var f File
		if err := json.Unmarshal([]byte(val), &f); err == nil {
			c.hits.Add(1)

			return f, nil
		}
	}

	// Cache miss
	c.misses.Add(1)
	slog.Debug("cache miss", "key", key)
	fileInfo, err := c.impl.Stat(path)
	if err != nil {
		return
	}

	// Serialize and cache
	// Type assert to ensure we capture ContentType and Path
	info = ParseToFile(fileInfo)

	bytes, err := json.Marshal(info)
	if err == nil {
		c.cache.Do(ctx, c.cache.B().Set().Key(key).Value(string(bytes)).Ex(c.ttl).Build())
	}

	return
}

func (c *CachedClient) revalidateStat(ctx context.Context) {
	startTime := time.Now()
	c.scanAndProcess(ctx, keyStat+"*", func(key string) error {
		path := strings.TrimPrefix(key, keyStat)
		info, err := c.impl.Stat(path)
		if err != nil {
			c.cache.Do(ctx, c.cache.B().Del().Key(key).Build())
			return err
		}

		// Serialize and cache
		f := ParseToFile(info)
		bytes, err := json.Marshal(f)
		if err == nil {
			c.cache.Do(ctx, c.cache.B().Set().Key(key).Value(string(bytes)).Ex(c.ttl).Build())
		}
		return nil
	})
	slog.Debug("revalidation of Stat complete", "duration", time.Since(startTime))
}
