package cache

import (
	"io"
	"time"
)

type RemoteLoader struct {
	file    *CacheFile
	loaders []*OpenLoader
}

type OpenLoader struct {
	reader       io.ReadCloser
	pos          int64
	lastUsedTime time.Time
}

func newRemoteLoader(file *CacheFile) *RemoteLoader {
	return &RemoteLoader{
		file:    file,
		loaders: make([]*OpenLoader, 2),
	}
}

func (r *RemoteLoader) Load(p []byte, pos int64) (n int, err error) {
	replaceIdx := -1
	for i := 0; i < len(r.loaders); i++ {
		loader := r.loaders[i]
		if loader == nil {
			replaceIdx = i
			continue
		}

		// 找到一个position刚好等于off的loader
		if loader.pos == pos {
			loader.lastUsedTime = time.Now()
			n, err = io.ReadFull(loader.reader, p)
			loader.pos += int64(n)
			if err != nil {
				loader.reader.Close()
				r.loaders[i] = nil
			}
			return
		}

		if replaceIdx == -1 || r.loaders[replaceIdx] != nil && r.loaders[replaceIdx].lastUsedTime.After(loader.lastUsedTime) {
			replaceIdx = i
		}
	}

	if r.loaders[replaceIdx] != nil {
		r.loaders[replaceIdx].reader.Close()
		r.loaders[replaceIdx] = nil
	}

	loader, err := r.newLoader(pos)
	if err != nil {
		return 0, err
	}
	loader.lastUsedTime = time.Now()

	r.loaders[replaceIdx] = loader
	n, err = io.ReadFull(loader.reader, p)
	loader.pos += int64(n)
	if err != nil {
		loader.reader.Close()
		r.loaders[replaceIdx] = nil
	}
	return
}

func (r *RemoteLoader) Close() {
	for i := 0; i < len(r.loaders); i++ {
		if r.loaders[i] != nil {
			r.loaders[i].reader.Close()
		}
	}
}

func (r *RemoteLoader) newLoader(pos int64) (*OpenLoader, error) {
	detail, err := r.file.cache.db.Object().GetDetail(r.file.cache.db.DefCtx(), r.file.remoteObj.ObjectID)
	if err != nil {
		return nil, err
	}

	down, err := r.file.cache.downloader.DownloadObjectByDetail(detail, pos, -1)
	if err != nil {
		return nil, err
	}

	return &OpenLoader{
		reader: down.File,
		pos:    pos,
	}, nil
}
