package pimport

import (
	"strconv"
	"time"

	"github.com/pingcap/dbaas/central/metrics"
	pimport "github.com/pingcap/dbaas/central/model/import"
	importservice "github.com/pingcap/dbaas/central/service/import"
	"github.com/pingcap/log"

	"github.com/prometheus/client_golang/prometheus"
	"go.uber.org/zap"
)

const recentFailDuration = time.Second * 120

// RegisterMetrics registers the metrics which are ONLY used in DbaaS server.
func RegisterMetrics() {
	prometheus.MustRegister(metrics.ImportThroughputBytes)
	prometheus.MustRegister(newCollector())
	prometheus.MustRegister(NewStatusCollector())
}

var _ prometheus.Collector = &ImportCollector{}

type ImportCollector struct {
}

func newCollector() *ImportCollector {
	return &ImportCollector{}
}

func (c *ImportCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- metrics.SyncingImportSinceCreatedSeconds
	ch <- metrics.RecentFailImports
}

func (c *ImportCollector) Collect(ch chan<- prometheus.Metric) {
	err := c.collect(ch)
	if err != nil {

		log.Error("failed to collect metrics", zap.Error(err))
	}
}

func (c *ImportCollector) collect(ch chan<- prometheus.Metric) error {
	var start = time.Now()
	defer func() {
		log.Info("imports metrics collect time", zap.Int64("time", time.Since(start).Milliseconds()))
	}()
	imports, err := pimport.ImportsToSync(nil)
	if err != nil {
		return err
	}

	for _, imp := range imports {
		dur := time.Since(imp.CreatedAt).Seconds()
		ch <- prometheus.MustNewConstMetric(
			metrics.SyncingImportSinceCreatedSeconds,
			prometheus.GaugeValue,
			dur,
			strconv.FormatUint(imp.Cluster.TenantID.Uint64(), 10),
			strconv.FormatUint(imp.ClusterID.Uint64(), 10),
			strconv.FormatUint(imp.ID.Uint64(), 10),
			metrics.GetProviderType(imp.Cluster.Free),
			imp.Status.String(),
		)
	}

	imports, err = pimport.FailImportsInRecent(nil /*tenantID*/, recentFailDuration)
	if err != nil {
		return err
	}

	for _, imp := range imports {
		dur := time.Since(imp.CreatedAt).Seconds()
		ch <- prometheus.MustNewConstMetric(
			metrics.RecentFailImports,
			prometheus.GaugeValue,
			dur,
			strconv.FormatUint(imp.Cluster.TenantID.Uint64(), 10),
			strconv.FormatUint(imp.ClusterID.Uint64(), 10),
			strconv.FormatUint(imp.ID.Uint64(), 10),
			metrics.GetProviderType(imp.Cluster.Free),
			importservice.PrettyMessage(imp.Message),
		)
	}

	return nil
}
