package config

import (
	"errors"
	"fmt"
	"os"
	"runtime"
	"strconv"
)

type Environment int

const (
	EnvDevelopment Environment = iota
	EnvProduction
)

type FileStore int

const (
	FileSystemStore = iota
	S3Store
)

type Config struct {
	Environment          Environment
	BindAddr             string
	TLSCertFile          string
	TLSKeyFile           string
	DatabaseURL          string
	FileStore            FileStore
	FileStoreHTTPRoot    string
	FileStoreHTTPBaseURL string
	AWSAccessKeyID       string
	AWSSecretAccessKey   string
	AWSRegion            string
	S3Bucket             string
	AssetsHTTPRoot       string
	FFmpegWorkerPoolSize int
}

func NewFromEnv() (Config, error) {
	envString := os.Getenv("ENV")
	var env Environment
	switch envString {
	case "production":
		env = EnvProduction
	case "development":
		env = EnvDevelopment
	case "":
		return Config{}, errors.New("ENV not set")
	default:
		return Config{}, fmt.Errorf("invalid ENV value: %s", envString)
	}

	bindAddr := os.Getenv("BIND_ADDR")
	if bindAddr == "" {
		bindAddr = "localhost:8888"
	}

	tlsCertFile := os.Getenv("TLS_CERT_FILE")
	tlsKeyFile := os.Getenv("TLS_KEY_FILE")
	if (tlsCertFile == "" && tlsKeyFile != "") || (tlsCertFile != "" && tlsKeyFile == "") {
		return Config{}, errors.New("both TLS_CERT_FILE and TLS_KEY_FILE must be set")
	}

	databaseURL := os.Getenv("DATABASE_URL")
	if databaseURL == "" {
		return Config{}, errors.New("DATABASE_URL not set")
	}

	fileStoreString := os.Getenv("FILE_STORE")
	var fileStore FileStore
	switch os.Getenv("FILE_STORE") {
	case "s3":
		fileStore = S3Store
	case "filesystem", "":
		fileStore = FileSystemStore
	default:
		return Config{}, fmt.Errorf("invalid FILE_STORE value: %s", fileStoreString)
	}

	fileStoreHTTPBaseURL := os.Getenv("FILE_STORE_HTTP_BASE_URL")
	if fileStoreHTTPBaseURL == "" {
		fileStoreHTTPBaseURL = "/"
	}

	var awsAccessKeyID, awsSecretAccessKey, awsRegion, s3Bucket, fileStoreHTTPRoot string
	if fileStore == S3Store {
		awsAccessKeyID = os.Getenv("AWS_ACCESS_KEY_ID")
		if awsAccessKeyID == "" {
			return Config{}, errors.New("AWS_ACCESS_KEY_ID not set")
		}

		awsSecretAccessKey = os.Getenv("AWS_SECRET_ACCESS_KEY")
		if awsSecretAccessKey == "" {
			return Config{}, errors.New("AWS_SECRET_ACCESS_KEY not set")
		}

		awsRegion = os.Getenv("AWS_REGION")
		if awsRegion == "" {
			return Config{}, errors.New("AWS_REGION not set")
		}

		s3Bucket = os.Getenv("S3_BUCKET")
		if s3Bucket == "" {
			return Config{}, errors.New("S3_BUCKET not set")
		}
	} else {
		if fileStoreHTTPRoot = os.Getenv("FILE_STORE_HTTP_ROOT"); fileStoreHTTPRoot == "" {
			return Config{}, errors.New("FILE_STORE_HTTP_ROOT not set")
		}
	}

	assetsHTTPRoot := os.Getenv("ASSETS_HTTP_ROOT")

	ffmpegWorkerPoolSize := runtime.NumCPU()
	if s := os.Getenv("FFMPEG_WORKER_POOL_SIZE"); s != "" {
		if n, err := strconv.Atoi(s); err != nil {
			return Config{}, fmt.Errorf("invalid FFMPEG_WORKER_POOL_SIZE value: %s", s)
		} else {
			ffmpegWorkerPoolSize = n
		}
	}

	return Config{
		Environment:          env,
		BindAddr:             bindAddr,
		TLSCertFile:          tlsCertFile,
		TLSKeyFile:           tlsKeyFile,
		DatabaseURL:          databaseURL,
		FileStore:            fileStore,
		AWSAccessKeyID:       awsAccessKeyID,
		AWSSecretAccessKey:   awsSecretAccessKey,
		AWSRegion:            awsRegion,
		S3Bucket:             s3Bucket,
		AssetsHTTPRoot:       assetsHTTPRoot,
		FileStoreHTTPRoot:    fileStoreHTTPRoot,
		FileStoreHTTPBaseURL: fileStoreHTTPBaseURL,
		FFmpegWorkerPoolSize: ffmpegWorkerPoolSize,
	}, nil
}
