package lightning

import (
	"context"
	"errors"
	"path/filepath"
	"time"

	"github.com/pingcap/tidb/br/pkg/storage"
	"github.com/tidbcloud/pkgv2/log"
	"go.uber.org/zap"
)

type azblobObjectLister struct {
	blobStorage *storage.AzureBlobStorage
}

type azblobResut struct {
	err  error
	data *ObjectInfo
}

// ListObjects list objects for an S3 data source, and returns an iterator.
// It implements the ObjectLister interface.
func (l *azblobObjectLister) ListObjects(ctx context.Context, req *ListRequest) (ListResultIterator, error) {

	logger := log.WithContextL(ctx)
	var opt storage.WalkOption
	if req.StartOffsetKey != "" {
		opt.ObjPrefix = req.StartOffsetKey
	}
	if req.MaxKeys > 0 {
		opt.ListCount = int64(req.MaxKeys)
	}

	resultch := make(chan azblobResut)
	ctx, cancel := context.WithTimeout(ctx, time.Minute)
	go func() {
		defer cancel()
		defer close(resultch)
		err := l.blobStorage.WalkDir(ctx, &opt, func(path string, size int64) error {
			select {
			case resultch <- azblobResut{
				data: &ObjectInfo{
					Name:   path,
					Size:   size,
					Prefix: filepath.Dir(path),
				},
			}:
			case <-ctx.Done():
				return errors.New("azblob workdir timeout")
			}
			return nil
		})
		if err != nil {
			logger.Warn("azblob workdir failed", zap.String("azblobUrl", l.blobStorage.URI()), zap.Any("request", req), zap.Error(err))
			select {
			case resultch <- azblobResut{err: err}:
			case <-ctx.Done():
			}
		}
	}()
	return &azblobListResultIterator{
		resultch: resultch,
	}, nil
}

type azblobListResultIterator struct {
	resultch chan azblobResut
}

// Next retrieves one azblob object and ready to fetch the next.
// It implements the ListResultIterator interface.
func (iter *azblobListResultIterator) Next() (*ObjectInfo, error) {
	result, ok := <-iter.resultch
	if !ok {
		return nil, errListDone
	}
	return result.data, result.err
}
