package fsutils

import (
	"fmt"
	"io/ioutil"
	"sync"

	"github.com/golangci/golangci-lint/pkg/logutils"

	"github.com/pkg/errors"
)

type FileCache struct {
	files sync.Map
}

func NewFileCache() *FileCache {
	return &FileCache{}
}

func (fc *FileCache) GetFileBytes(filePath string) ([]byte, error) {
	cachedBytes, ok := fc.files.Load(filePath)
	if ok {
		return cachedBytes.([]byte), nil
	}

	fileBytes, err := ioutil.ReadFile(filePath)
	if err != nil {
		return nil, errors.Wrapf(err, "can't read file %s", filePath)
	}

	fc.files.Store(filePath, fileBytes)
	return fileBytes, nil
}

func prettifyBytesCount(n int) string {
	const (
		Multiplexer = 1024
		KiB         = 1 * Multiplexer
		MiB         = KiB * Multiplexer
		GiB         = MiB * Multiplexer
	)

	if n >= GiB {
		return fmt.Sprintf("%.1fGiB", float64(n)/GiB)
	}
	if n >= MiB {
		return fmt.Sprintf("%.1fMiB", float64(n)/MiB)
	}
	if n >= KiB {
		return fmt.Sprintf("%.1fKiB", float64(n)/KiB)
	}
	return fmt.Sprintf("%dB", n)
}

func (fc *FileCache) PrintStats(log logutils.Log) {
	var size int
	var mapLen int
	fc.files.Range(func(_, fileBytes interface{}) bool {
		mapLen++
		size += len(fileBytes.([]byte))

		return true
	})

	log.Infof("File cache stats: %d entries of total size %s", mapLen, prettifyBytesCount(size))
}
