// Package storage abstracts photo object storage. Selection follows the
// backend's convention (backend/src/lib/storage.ts): S3 when S3_ENDPOINT
// and S3_BUCKET are both set, local disk otherwise. Keys are identical on
// both backends: galleries/<galleryID>/<variantDir>/<photoID>.<ext>.
package storage

import (
	"context"
	"errors"
	"fmt"
	"io"
	"time"

	"git.azzamo.net/Michilis/Spanglish/photo-api/internal/config"
)

// ErrNoPresign is returned by backends that cannot presign (local disk);
// callers then stream the object through the API instead.
var ErrNoPresign = errors.New("presigned URLs not supported")

// ErrNotExist is what Stat reports for a missing object on either backend.
var ErrNotExist = errors.New("object does not exist")

type Storage interface {
	Put(ctx context.Context, key string, r io.Reader, size int64, contentType string) error
	Open(ctx context.Context, key string) (io.ReadCloser, int64, error)
	// Stat returns the object's size without reading it, or ErrNotExist.
	Stat(ctx context.Context, key string) (int64, error)
	Delete(ctx context.Context, key string) error
	PresignGet(ctx context.Context, key, downloadFilename, contentType string, expiry time.Duration) (string, error)
}

// New builds the backend that serves requests (see config.S3Enabled).
func New(cfg config.Config) (Storage, error) {
	if cfg.S3Enabled() {
		return NewS3(cfg)
	}
	return NewLocal(cfg.StoragePath)
}

// Name describes a backend for log lines.
func Name(cfg config.Config, s Storage) string {
	if _, ok := s.(*s3Store); ok {
		return fmt.Sprintf("S3 bucket %s at %s", cfg.S3Bucket, cfg.S3Endpoint)
	}
	return fmt.Sprintf("local disk at %s", cfg.StoragePath)
}
