package app

import (
	"time"

	"code.tnxs.net/work/lib/app/logger"
	"go.uber.org/zap/zapcore"
)

// Worker describes how many service workers to launch
type Worker struct {
	ChannelSize int64 `mapstructure:"channel_size,omitempty"`
	WorkerCount int   `mapstructure:"worker_count,omitempty"`
}

// CacheSize describes how to chunkify resources
type CacheSize struct {
	Increment int64
}

// Metrics defines the if and where to collect data
type Metrics struct {
	Address string `mapstructure:"address,omitempty"`
	Enabled bool   `mapstructure:"enabled,omitempty"`
}

// Endpoint describes a web URL as a service endpoint
type Endpoint struct {
	BasePath string `mapstructure:"base_path,omitempty"`
	Host     string `mapstructure:"host,omitempty"`
	Scheme   string `mapstructure:"scheme,omitempty"`
}

type Email struct {
	FromAddress     string `mapstructure:"from_address,omitempty"`
	FromName        string `mapstructure:"from_name,omitempty"`
	ServiceProvider string `mapstructure:"service_provider,omitempty"`
	SMTPHost        string `mapstructure:"smtp_host,omitempty"`
	SMTPPort        string `mapstructure:"smtp_port,omitempty"`
	SMTPPassword    string `mapstructure:"smtp_password,omitempty"`
	SMTPUsername    string `mapstructure:"smtp_username,omitempty"`
}

// Chunk defines cache chunk size
type Chunk struct {
	size int32 `mapstructure:"size,omitempty"`
}

// ServiceAccount defines and external service
type ServiceAccount struct {
	APIKey             string        `mapstructure:"api_key,omitempty"`
	ApplicationName    string        `mapstructure:"application_name,omitempty"`
	AuthenticationType string        `mapstructure:"authentication_type,omitempty"`
	BackendID          string        `mapstructure:"backend_id,omitempty"`
	ClientID           string        `mapstructure:"client_id,omitempty"`
	ClientSecret       string        `mapstructure:"client_secret,omitempty"`
	DSN                string        `mapstructure:"dsn,omitempty"`
	Endpoint           Endpoint      `mapstructure:"endpoint,omitempty"`
	Password           string        `mapstructure:"password,omitempty"`
	Production         bool          `mapstructure:"production,omitempty"`
	SecurityToken      string        `mapstructure:"security_token,omitempty"`
	Credentials        string        `mapstructure:"credentials,omitempty"`
	Timeout            time.Duration `mapstructure:"timeout,omitempty"`
	Type               string        `mapstructure:"type,omitempty"`
	Username           string        `mapstructure:"username,omitempty"`
	Vendor             string        `mapstructure:"vendor,omitempty"`
}

// Configuration defines the config struct
type Configuration struct {
	AppName         string                    `mapstructure:"app_name,omitempty"`
	BackendID       string                    `mapstructure:"backend_id,omitempty"`
	BuildEnv        string                    `mapstructure:"build_env,omitempty"`
	CacheSizes      map[string]CacheSize      `mapstructure:"cache_sizes,omitempty"`
	ClusterID       string                    `mapstructure:"cluster_id,omitempty"`
	Chunks          map[string]Chunk          `mapstructure:"chunks,omitempty"`
	DBMS            string                    `mapstructure:"dbms,omitempty"`
	DBMSHost        string                    `mapstructure:"dbms_host,omitempty"`
	DBMSName        string                    `mapstructure:"dbms_name,omitempty"`
	DBMSPassword    string                    `mapstructure:"dbms_password,omitempty"`
	DBMSUsername    string                    `mapstructure:"dbms_username,omitempty"`
	DSN             string                    `mapstructure:"dsn,omitempty"`
	Email           map[string]Email          `mapstructure:"email,omitempty"`
	Endpoint        Endpoint                  `mapstructure:"endpoint,omitempty"`
	Environment     string                    `mapstructure:"environment,omitempty"`
	GelfURI         string                    `mapstructure:"gelf_uri,omitempty"`
	GitHubOrgName   string                    `mapstructure:"git_hub_org_name,omitempty"`
	LogLevel        int                       `mapstructure:"log_level,omitempty"`
	Metrics         Metrics                   `mapstructure:"metrics,omitempty"`
	KafkaServer     string                    `mapstructure:"kafka_server,omitempty"`
	PDFRenderEngine string                    `mapstructure:"pdf_render_engine,omitempty"`
	RegistryPriv    string                    `mapstructure:"registry_priv,omitempty"`
	RegistryPublic  string                    `mapstructure:"registry_public,omitempty"`
	RepoName        string                    `mapstructure:"repo_name,omitempty"`
	ServiceAccounts map[string]ServiceAccount `mapstructure:"service_accounts,omitempty"`
	ShutdownTimeout time.Duration             `mapstructure:"shutdown_timeout,omitempty"`
	Version         string                    `mapstructure:"version,omitempty"`
	Workers         map[string]Worker         `mapstructure:"workers,omitempty"`
}

// GetCacheSize returns the named cache size
func GetCacheSize(name string) int64 {
	obj, ok := config.CacheSizes[name]
	if ok {
		return obj.Increment
	}
	sugar.Warnf("app.GetCacheSize: unknown cache size identifier: %s", name)
	return 0
}

// GetPDFRenderEngine returns a config file parameter
func GetPDFRenderEngine() string {
	return config.PDFRenderEngine
}

// GetKafkaServer returns a config file parameter
func GetKafkaServer() string {
	if config.KafkaServer != "" {
		return config.KafkaServer
	}
	return "nats.fabric.tnxs.net"
}

// GetChunkSize returns a config file parameter
func GetChunkSize(chunkName string) int {
	obj, ok := config.Chunks[chunkName]
	if ok {
		return int(obj.size)
	}
	return 0
}

// GetMetricsAddress return the metrics Address value
func GetMetricsAddress() string {
	return config.Metrics.Address
}

// IsMetrics returns TRUE if metrics enabled
func IsMetrics() bool {
	return config.Metrics.Enabled
}

// GetWorker returns the named worker record
func GetWorker(name string) *Worker {
	worker, ok := config.Workers[name]
	if ok {
		return &worker
	}
	return nil
}

// GetEmail returns the named email record
func GetEmail(name string) *Email {
	email, ok := config.Email[name]
	if ok {
		return &email
	}
	return nil
}

// GetServiceAccount returns the named service account struct
func GetServiceAccount(name string) *ServiceAccount {
	serviceaccount, ok := config.ServiceAccounts[name]
	if ok {
		return &serviceaccount
	}
	sugar.Errorf("app.config: 💣⛔ unknown service account: %s", name)
	return nil
}

// GetDBMSHost returns the parameter
func GetDBMSHost() string {
	return config.DBMSHost
}

// GetDBMSName returns the parameter
func GetDBMSName() string {
	return config.DBMSName
}

// GetDBMSPassword returns the parameter
func GetDBMSPassword() string {
	return config.DBMSPassword
}

// GetDBMSUsername returns the parameter
func GetDBMSUsername() string {
	return config.DBMSUsername
}

// GetAppName retrieves the Taxnexus App Name for this microservice
func GetAppName() string {
	return config.AppName
}

// GetEnvironment retrieves the current runtime environment
func GetEnvironment() string {
	return config.Environment
}

// GetBackendID retrieves the backend ID
func GetBackendID() string {
	return config.BackendID
}

// GetClusterID retrieves the cluster ID
func GetClusterID() string {
	return config.ClusterID
}

// GetDSN retrieves the Taxnexus database DSN for this microservice
func GetDSN() string {
	return config.DSN
}

// GetDBMS retrieves the DBMS string
func GetDBMS() string {
	return config.DBMS
}

// GetLogLevel returns the Log Level
func GetLogLevel() zapcore.Level {
	switch config.LogLevel {
	case int(logger.DebugLevel):
		return logger.DebugLevel
	case int(logger.InfoLevel):
		return logger.InfoLevel
	case int(logger.WarnLevel):
		return logger.WarnLevel
	case int(logger.ErrorLevel):
		return logger.ErrorLevel
	case int(logger.PanicLevel):
		return logger.PanicLevel
	default:
		return logger.DebugLevel
	}
}
