package config

import (
	"time"

	"github.com/BurntSushi/toml"
	"github.com/juju/errors"
	"github.com/pingcap/schrodinger/pkg/elasticsearch"
	sjira "github.com/pingcap/schrodinger/pkg/jira"
	"github.com/pingcap/schrodinger/pkg/kibana"
	"github.com/pingcap/schrodinger/pkg/parser"
)

// Config contains configuration options.
type Config struct {
	Host string `toml:"host"`
	Port int    `toml:"port"`

	Storage          Storage      `toml:"storage"`
	KubeConfig       KubeConfig   `toml:"kube-config"`
	Controller       Controller   `toml:"controller"`
	Experiment       Experiment   `toml:"experiment"`
	Cat              Cat          `toml:"cat"`
	Test             Test         `toml:"test"`
	Agent            Agent        `toml:"agent"`
	Daemon           Daemon       `toml:"daemon"`
	Image            Image        `toml:"image"`
	Build            Build        `toml:"build"`
	Label            Label        `toml:"label"`
	Util             Util         `toml:"util"`
	Notifiers        Notifiers    `toml:"notifiers"`
	Jira             sjira.Config `toml:"jira"`
	JumpServerHost   string       `toml:"jumpserver-host"`
	JumpServerPasswd string       `toml:"jumpserver-passwd"`
	LogService       Log          `toml:"log"`
}

// Log defines the config for log service.
// We get the log address of cat and test from log service.
type Log struct {
	Kibana  kibana.Config        `toml:"kibana"`
	Elastic elasticsearch.Config `toml:"elasticsearch"`
}

// Storage is the storage section of the config.
type Storage struct {
	Driver       string `toml:"driver"`
	Datasource   string `toml:"datasource"`
	MaxIdleConns int    `toml:"max-idle-conns"`
}

// Controller is controller section of the config.
type Controller struct {
	MonitorInterval parser.Duration `toml:"monitor-interval"`
}

// Experiment is experiment section of the config
type Experiment struct {
	SyncInterval parser.Duration `toml:"sync-interval"`
}

// KubeConfig defines the config of kubebernetes
type KubeConfig struct {
	ConfigPath string `toml:"config-path"`
	ChartPath  string `toml:"chart-path"`
	TillerPort int    `toml:"tiller-port"`
	Namespace  string `toml:"namespace"`
}

// Cat is cat section of the config
type Cat struct {
	TidbLease          int64  `toml:"tidb-lease"`
	MonitorReserveDays int32  `toml:"monitor-reserve-days"`
	RetentionDuration  string `toml:"retention-duration"`
	AgentPort          int    `toml:"agent-port"`
	PdServicePort      int    `toml:"pd-service-port"`
	TidbServicePort    int    `toml:"tidb-service-port"`
	TikvServicePort    int    `toml:"tikv-service-port"`
	PdDataDir          string `toml:"pd-data-dir"`
	TikvDataDir        string `toml:"tikv-data-dir"`
	ConfigMap          string `toml:"config-map"`
}

// Test is test section of the config
type Test struct {
	SyncInterval parser.Duration `toml:"sync-interval"`
	Expirer      parser.Duration `toml:"expirer"`
	RetryTimes   int64           `toml:"retry-times"`
	LogLines     int64           `toml:"log-lines"`
	PublicNode   string          `toml:"public-node"`
}

// Agent is agent section of the config
type Agent struct {
	RestartLimit    int32           `toml:"restart-limit"`
	RestartInterval int32           `toml:"restart-interval"`
	Timeout         parser.Duration `toml:"timeout"`
}

// Daemon is daemon section of the config
type Daemon struct {
	Port int `toml:"port"`
}

// Image is image section of the config
type Image struct {
	DockerhubPrefix string `toml:"dockerhub-prefix"`
	Prometheus      string `toml:"prometheus"`
	Grafana         string `toml:"grafana"`
	Dashboard       string `toml:"dashboard"`
	Pushgateway     string `toml:"pushgateway"`
}

// Build is buid section of the config
type Build struct {
	MaxRetry          int64 `toml:"max-retry"`
	RequestBufferSize int64 `toml:"request-buffer-size"`
}

// Label is label section of the config
type Label struct {
	IdcKey string `toml:"idc-key"`
}

// Notifiers is notify section of the config
type Notifiers struct {
	Slack Slack        `toml:"slack"`
	Time  NotifierTime `toml:"time"`
}

// Slack is slack section of the conf
type Slack struct {
	Token    string `toml:"token"`
	Channel  string `toml:"channel"`
	Username string `toml:"username"`
}

// NotifierTime is threshold of notifier of the conf
type NotifierTime struct {
	DestroyThreshold int `toml:"destroy_threshold"`
	LoopInterval     int `toml:"loop_interval"`
}

// Util is util section of the conf
type Util struct {
	SQLRetryTime          int             `toml:"sql-retry"`
	LogPrefix             string          `toml:"log-prefix"`
	DownloadAddrPrefix    string          `toml:"download-addr-prefix"`
	DefaultIdc            string          `toml:"default-idc"`
	PageSize              int64           `toml:"page-size"`
	GithubMonitorInterval parser.Duration `toml:"github-monitor-interval"`
	ManagerDomain         string          `toml:"manager-domain"`
}

var globalConf = Config{
	Host: "172.16.30.12",
	Port: 60000,
	Storage: Storage{
		Driver:       "mysql",
		Datasource:   "root:@(localhost:4000)/schrodinger",
		MaxIdleConns: 128,
	},
	KubeConfig: KubeConfig{
		ConfigPath: "/home/pingcap/.kube/config",
		ChartPath:  "./charts",
		Namespace:  "pingcap",
		TillerPort: 30790,
	},
	Controller: Controller{
		MonitorInterval: parser.Duration{Duration: 60 * time.Second},
	},
	Experiment: Experiment{
		SyncInterval: parser.Duration{Duration: 300 * time.Second},
	},
	Cat: Cat{
		TidbLease:          5,
		MonitorReserveDays: 10,
		RetentionDuration:  "2h",
		AgentPort:          8350,
		PdServicePort:      2379,
		TidbServicePort:    4000,
		TikvServicePort:    20160,
		PdDataDir:          "/var/lib/pd/data",
		TikvDataDir:        "/var/lib/tikv/data",
		ConfigMap:          "tidb-cluster-config-template",
	},
	Test: Test{
		SyncInterval: parser.Duration{Duration: 300 * time.Second},
		Expirer:      parser.Duration{Duration: 4 * time.Hour},
		RetryTimes:   5,
		LogLines:     500,
		PublicNode:   "172.16.30.11",
	},
	Agent: Agent{
		RestartInterval: 2,
		RestartLimit:    2,
		Timeout:         parser.Duration{Duration: 480 * time.Hour},
	},
	Daemon: Daemon{
		Port: 8888,
	},
	Image: Image{
		DockerhubPrefix: "127.0.0.1:5001",
		Prometheus:      "uhub.ucloud.cn/pingcap/prometheus:v2.0.0",
		Grafana:         "uhub.ucloud.cn/pingcap/grafana:4.6.3",
		Dashboard:       "pingcap/tidb-dashboard-installer:v2.0.0",
		Pushgateway:     "uhub.ucloud.cn/pingcap/pushgateway:v0.3.1",
	},
	Build: Build{
		MaxRetry:          3,
		RequestBufferSize: 5,
	},
	Label: Label{
		IdcKey: "idc",
	},
	Util: Util{
		SQLRetryTime:          3,
		LogPrefix:             "/mnt/ceph/schrodinger/log/hash",
		DownloadAddrPrefix:    "http://pingcap-dev.hk.ufileos.com",
		DefaultIdc:            "idc",
		PageSize:              10,
		GithubMonitorInterval: parser.Duration{Duration: 10 * time.Minute},
		ManagerDomain:         "schrodinger.pingcap.net",
	},
	Notifiers: Notifiers{
		Slack: Slack{
			Channel:  "#schrodinger-alert",
			Username: "schrodinger_bot",
			Token:    "xoxb-338269940566-EqbYEgr8kg007mVEqWdY4gwT",
		},
	},
	Jira: sjira.Config{
		UserName:  "sre-bot@pingcap.com",
		Password:  "",
		BaseURL:   "https://internal.pingcap.net/jira/",
		Project:   "TRR",
		IssueType: "Schrodinger Test Record",
	},
	JumpServerHost:   "pingcap@172.16.4.4",
	JumpServerPasswd: "",
	LogService: Log{
		Kibana: kibana.Config{
			Address: "http://172.16.4.4:30750",
			Index:   "d575b240-bdc8-11e9-a168-b9df9becdde7",
		},
	},
}

// GetGlobalConfig returns the global configuration for this server.
func GetGlobalConfig() *Config {
	return &globalConf
}

// Load loads config options from a toml file.
func (c *Config) Load(confFile string) error {
	_, err := toml.DecodeFile(confFile, c)
	return errors.Trace(err)
}
