package filesystem

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

const keyReadDir = "webdav:readdir:"

func (c *CachedClient) ReadDir(path string) ([]os.FileInfo, error) {
	key := keyReadDir + 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 cached []File
		if err := json.Unmarshal([]byte(val), &cached); err == nil {
			c.readDirHits.Add(1)
			c.hits.Add(1)
			infos := make([]os.FileInfo, len(cached))
			for i, f := range cached {
				infos[i] = f
			}
			return infos, nil
		}
	}

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

	// Serialize and cache
	cached := make([]File, 0, len(infos))
	for _, info := range infos {
		cached = append(cached, ParseToFile(info))
	}

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

	return infos, nil
}

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

		// Serialize and cache
		cached := make([]File, 0, len(infos))
		for _, info := range infos {
			cached = append(cached, ParseToFile(info))
		}

		bytes, err := json.Marshal(cached)
		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 readDir complete", "duration", time.Since(startTime))
}
