package storage

import (
	"fmt"
	"os"
	"strings"
)

const (
	ProviderFilesystem = "filesystem"
	ProviderS3         = "s3"
)

type Config struct {
	Provider         string
	FilesystemRoot   string
	LegacyUploadRoot string
	Bucket           string
	Region           string
	Endpoint         string
	AccessKeyID      string
	SecretAccessKey  string
	SessionToken     string
	KeyPrefix        string
	UsePathStyle     bool
}

func LoadConfigFromEnv() Config {
	provider := strings.ToLower(strings.TrimSpace(os.Getenv("FILE_STORAGE_PROVIDER")))
	if provider == "" {
		if hasS3RuntimeHints() {
			provider = ProviderS3
		} else {
			provider = ProviderFilesystem
		}
	}

	root := strings.TrimSpace(os.Getenv("FILE_STORAGE_ROOT"))
	if root == "" {
		root = "data/object-storage"
	}

	legacyUploadRoot := strings.TrimSpace(os.Getenv("FILE_STORAGE_LEGACY_UPLOAD_ROOT"))
	if legacyUploadRoot == "" {
		legacyUploadRoot = "data/uploads"
	}

	return Config{
		Provider:         provider,
		FilesystemRoot:   root,
		LegacyUploadRoot: legacyUploadRoot,
		Bucket:           strings.TrimSpace(os.Getenv("FILE_STORAGE_BUCKET")),
		Region:           strings.TrimSpace(os.Getenv("FILE_STORAGE_REGION")),
		Endpoint:         strings.TrimSpace(os.Getenv("FILE_STORAGE_ENDPOINT")),
		AccessKeyID:      strings.TrimSpace(os.Getenv("FILE_STORAGE_ACCESS_KEY_ID")),
		SecretAccessKey:  strings.TrimSpace(os.Getenv("FILE_STORAGE_SECRET_ACCESS_KEY")),
		SessionToken:     strings.TrimSpace(os.Getenv("FILE_STORAGE_SESSION_TOKEN")),
		KeyPrefix:        strings.TrimSpace(os.Getenv("FILE_STORAGE_PREFIX")),
		UsePathStyle:     parseEnvBool("FILE_STORAGE_USE_PATH_STYLE"),
	}
}

func NewStoreFromEnv() (ObjectStore, error) {
	return NewStore(LoadConfigFromEnv())
}

func NewStore(cfg Config) (ObjectStore, error) {
	switch cfg.Provider {
	case ProviderFilesystem:
		return NewFilesystemStore(cfg.FilesystemRoot)
	case ProviderS3:
		return NewS3Store(cfg)
	default:
		return nil, fmt.Errorf("unsupported file storage provider %q", cfg.Provider)
	}
}

func parseEnvBool(name string) bool {
	value := strings.ToLower(strings.TrimSpace(os.Getenv(name)))
	switch value {
	case "1", "true", "yes", "on":
		return true
	default:
		return false
	}
}

func hasS3RuntimeHints() bool {
	for _, name := range []string{
		"FILE_STORAGE_BUCKET",
		"FILE_STORAGE_ENDPOINT",
		"FILE_STORAGE_ACCESS_KEY_ID",
		"FILE_STORAGE_SECRET_ACCESS_KEY",
		"AWS_ACCESS_KEY_ID",
		"AWS_SECRET_ACCESS_KEY",
		"AWS_PROFILE",
	} {
		if strings.TrimSpace(os.Getenv(name)) != "" {
			return true
		}
	}
	return false
}
