package storage

import (
	"context"
	"errors"
	"fmt"
	"io"
	"path/filepath"
	"regexp"
	"strings"

	"tangled.org/core/spindle/config"
)

var ErrNotExist = errors.New("storage: object does not exist")

type Storage interface {
	Get(ctx context.Context, key string) (io.ReadCloser, error)
	Put(ctx context.Context, key string, r io.Reader) error
	Delete(ctx context.Context, key string) error
}

var keyRe = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._:/@%+=-]{0,511}$`)

func ValidateKey(key string) error {
	if !keyRe.MatchString(key) {
		return fmt.Errorf("storage: invalid key %q", key)
	}
	for _, seg := range strings.Split(key, "/") {
		if seg == "" || seg == "." || seg == ".." {
			return fmt.Errorf("storage: invalid key %q", key)
		}
	}
	return nil
}

func New(ctx context.Context, cfg *config.Config) (Storage, error) {
	switch cfg.Cache.Backend {
	case "":
		return nil, nil
	case "disk":
		dir := cfg.Cache.DiskDir
		if dir == "" {
			dir = filepath.Join(filepath.Dir(cfg.Server.DBPath), "cache")
		}
		return NewDisk(dir)
	case "s3":
		return NewS3(ctx, cfg.Cache.S3Bucket, cfg.Cache.S3Prefix)
	default:
		return nil, fmt.Errorf("storage: unknown backend %q", cfg.Cache.Backend)
	}
}
