// Copyright (C) 2022 Marius Schellenberger

package fs

import (
	"context"
	"os"
	"sync"
	"time"
)

const statExpiry = time.Minute * 5

type statCacheEntry struct {
	mtime time.Time
	fi    os.FileInfo
}

type StatCache struct {
	mu  sync.RWMutex
	ctx context.Context
	m   map[string]*statCacheEntry
}

func NewStatCache(ctx context.Context) *StatCache {
	sc := &StatCache{ctx: ctx, m: make(map[string]*statCacheEntry)}
	go sc.cleanup()
	return sc
}

func (sc *StatCache) cleanup() {
	t := time.NewTicker(statExpiry)
	defer t.Stop()
	for {
		select {
		case <-sc.ctx.Done():
			return
		case <-t.C:
		}
		sc.mu.Lock()
		now := time.Now()
		for k, sce := range sc.m {
			if now.After(sce.mtime) {
				delete(sc.m, k)
			}
		}
		sc.mu.Unlock()
	}
}

func (sc *StatCache) Get(name string) (os.FileInfo, error) {
	sc.mu.RLock()
	defer sc.mu.RUnlock()
	if sce, ok := sc.m[name]; ok {
		return sce.fi, nil
	}
	return nil, NoCacheEntry
}

func (sc *StatCache) Set(name string, fi os.FileInfo) {
	sc.mu.Lock()
	defer sc.mu.Unlock()
	sc.m[name] = &statCacheEntry{time.Now().Add(statExpiry), fi}
}
