// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.package spec

package manager

import (
	"errors"
	"time"

	"k8s.io/apimachinery/pkg/api/resource"

	"github.com/pingcap/tidb-cloud-manager/pkg/client"
	tiapi "github.com/pingcap/tidb-cloud-manager/pkg/tidbinstance/api"
)

const (
	promRetentionDays = 30 // prometheus default retention days
	// default version for docker images
	defaultVersion    = "latest" // default version for pd/tidb/tikv
	defaultChunks     = 64
	defaultThreads    = 16
	maxRetries        = 10
	clusterName       = "tidb-cluster"
	physicalShiftBits = 18 // shift bits to get commit TS
)

var (
	ClusterNotFound        = errors.New("tidb cluster not found")
	defaultTiKVRequestSize = resource.MustParse("50Gi")

	BackupDir  string
	RepoPrefix string
)

type PodStatus struct {
	Name   string `json:"name"`
	PodIP  string `json:"pod_ip"`
	NodeIP string `json:"node_ip"`
	Status string `json:"status"`
	Image  string `json:"image"`
}

type Cluster struct {
	Name               string            `json:"name"`
	Pd                 *tiapi.PodSpec    `json:"pd"`
	Tikv               *tiapi.PodSpec    `json:"tikv"`
	Tidb               *tiapi.PodSpec    `json:"tidb"`
	Monitor            *tiapi.PodSpec    `json:"monitor,omitempty"`
	ServiceType        string            `json:"service_type,omitempty"` // default service type is set at manager startup
	TidbLease          int               `json:"tidb_lease,omitempty"`   // this should be an advanced option
	MonitorReserveDays int               `json:"monitor_reserve_days,omitempty"`
	RootPassword       string            `json:"root_password,omitempty"`
	Labels             map[string]string `json:"labels,omitempty"` // store cluster level meta info
	Config             string            `json:"config,omitempty"`
	KafkaAddr          string            `json:"kafka_addr,omitempty"` // kafka where pump push binlog to
	Secrets            map[string]string `json:"scerets,omitempty"`    //

	// response info
	Deleted                bool        `json:"deleted,omitempty"`
	CreatedAt              time.Time   `json:"created_at,omitempty"`
	Initialized            bool        `json:"initialized,omitempty"` // whether initialization password is set
	TidbService            Service     `json:"tidb_service,omitempty"`
	PrometheusService      Service     `json:"prometheus_service,omitempty"`
	GrafanaService         Service     `json:"grafana_service,omitempty"`
	PrivilegedTiDBSerivice Service     `json:"privileged_tidb_service,omitempty"`
	PdStatus               []PodStatus `json:"pd_status,omitempty"`
	TidbStatus             []PodStatus `json:"tidb_status,omitempty"`
	TikvStatus             []PodStatus `json:"tikv_status,omitempty"`
}

type Service struct {
	NodeIP       []string `json:"node_ip,omitempty"` // if ServiceType is NodePort or LoadBalancer, NodeIP is all nodes' IP
	NodePort     int      `json:"node_port,omitempty"`
	ClusterIP    string   `json:"cluster_ip,omitempty"`
	ClusterPort  int      `json:"cluster_port,omitempty"`
	ExternalIP   string   `json:"external_ip,omitempty"`   // LoadBalancer IP
	ExternalPort int      `json:"external_port,omitempty"` // LoadBalancer Port
}

type Volume struct {
	Name           string `json:"name,omitempty"`
	Namespace      string `json:"namespace,omitempty"`
	App            string `json:"app",omitempty`
	Node           string `json:"node,omitempty"`
	HostPath       string `json:"host_path,omitempty"`
	Capacity       string `json:"capacity,omitempty"`
	Used           string `json:"used,omitempty"`
	Pod            string `json:"pod,omitempty"`
	Cluster        string `json:"cluster,omitempty"`
	Status         string `json:"status,omitempty"`
	ClusterID      string `json:"cluster_id,omitempty"`
	MemberID       string `json:"member_id,omitempty"`
	StoreID        string `json:"store_id,omitempty"`
	Tombstoned     bool   `json:"tombstoned,omitempty"`
	ClusterDeleted bool   `json:"clusterDeleted,omitempty"`
}

type Job struct {
	Name   string           `json:"name"`
	Status JobConditionType `json:"status"`
}

type JobConditionType string

// These are valid conditions of a job.
const (
	// JobComplete means the job has completed its execution
	JobComplete JobConditionType = "Complete"
	// JobFailed means the job has failed its execution
	JobFailed JobConditionType = "Failed"
	// JobRunning means the job has running its execution
	JobRunning JobConditionType = "Running"
	// JobUnknown means retrive the job's status failed
	JobUnknown JobConditionType = "Unknown"

	// AnnBackupDatabase is database annotation in backup job
	AnnBackupDatabase = "backup.pingcap.com/database"
	// AnnBackupDatabase is tables annotation in backup job
	AnnBackupTables = "backup.pingcap.com/tables"
	// AnnBackupDatabase is path annotation in backup job
	AnnBackupPath = "backup.pingcap.com/path"
	// AnnBackupDatabase is SavePoint annotation in backup job
	AnnBackupSavePoint = "backup.pingcap.com/savePoint"
)

type clusterConfig struct {
	MetricsAddr string
}

type Manager struct {
	ServiceType string
	Namespace   string

	Cli client.Interface
}

type Node struct {
	Name   string            `json:"name,omitempty"`
	IP     string            `json:"ip,omitempty"`
	Labels map[string]string `json:"labels,omitempty"`
	CPU    RequestsAndLimits `json:"cpu,omitempty"`
	Memory RequestsAndLimits `json:"memory,omitempty"`
}

type RequestsAndLimits struct {
	Requests ValAndFraction `json:"requests,omitempty"`
	Limits   ValAndFraction `json:"limits,omitempty"`
}

type ValAndFraction struct {
	Value    string `json:"value,omitempty"`
	Fraction string `json:"fraction,omitempty"`
}

//The summary store info for tikv instances
type TikvStoresSummary struct {
	//Count represents tikv's storage num with up status
	Count int `json:"count"`

	//MaxUsedStorage represents the tikv's storage that uses the most storage space
	MaxUsedStorage uint64 `json:"max_used_storage"`

	//MinAvailableStorage represents the tikv's storage that has the min available storage space
	MinAvailableStorage uint64 `json:"min_available_storage"`
}

// BackupParam is backup parameters
type BackupParam struct {
	// ImageVersion is tidb-enterprise-tools docker image version
	ImageVersion string            `json:"image_version",omitempty`
	NodeSelector map[string]string `json:"node_selector",omitempty`
	// Database is the database to backup
	Database string `json:"database",omitempty`
	// Tables is table list to backup
	Tables  []string `json:"tables",omitempty`
	Threads int      `json:"threads",omitempty`
	Chunks  int      `json:"chunks",omitempty`
}

type BackupStatus struct {
	Status    JobConditionType `json:"status",omitempty`
	SavePoint uint64           `json:"save_point",omitempty`
	Node      string           `json:"node",omitempty`
	Path      string           `json:"path",omitempty`
	Database  string           `json:"database",omitempty`
	Tables    []string         `json:"tables",omitempty`
}
