package metric

import (
	"context"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/tidbcloud/aws-shared-provider/pkg/auditlog/entity"
	"github.com/tidbcloud/aws-shared-provider/pkg/auditlog/repo"
	"github.com/tidbcloud/pkgv2/log"
	"go.uber.org/zap"
)

const AuditLogMaxRuningTime = 1 * time.Hour

var (
	AuditLogTaskRunningTime = prometheus.NewDesc(
		prometheus.BuildFQName(metricNamespace, "task", "duration_seconds"),
		"Duration in seconds to running audit log task",
		[]string{"task_id", "cluster_id", "state"},
		nil)

	AuditLogTaskCorruptedNumber = prometheus.NewDesc(
		prometheus.BuildFQName(metricNamespace, "task", "corrupted_number"),
		"audit log task corrupted number",
		nil,
		nil)
)

type AuditLogTaskMetricCollector struct {
	auditLogTaskRepo repo.AuditLogTaskRepo
}

func NewAuditLogTaskMetricCollector(auditLogTaskRepo repo.AuditLogTaskRepo) *AuditLogTaskMetricCollector {
	return &AuditLogTaskMetricCollector{
		auditLogTaskRepo: auditLogTaskRepo,
	}
}

func (a *AuditLogTaskMetricCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- AuditLogTaskRunningTime
	ch <- AuditLogTaskCorruptedNumber
}

func (a *AuditLogTaskMetricCollector) Collect(ch chan<- prometheus.Metric) {
	ctx := context.Background()
	logger := log.WithContextL(ctx)
	logger.Info("start to collect audit log task metric")

	tasks, err := a.auditLogTaskRepo.List(ctx, &entity.ListAuditLogTaskOptions{
		States: []entity.AuditLogTaskState{
			entity.AuditLogTaskStatePending,
			entity.AuditLogTaskStateRunning,
			entity.AuditLogTaskStateCorrupted,
			entity.AuditLogTaskStateFailed,
		},
	})
	if err != nil {
		log.Error(ctx, "failed to list audit log task", zap.Error(err))
		return
	}

	corrupted := 0
	for _, task := range tasks {
		if task.State == entity.AuditLogTaskStateCorrupted {
			corrupted++
			continue
		}
		duration := time.Since(task.CreatedAt)
		if duration > AuditLogMaxRuningTime {
			ch <- prometheus.MustNewConstMetric(
				AuditLogTaskRunningTime,
				prometheus.GaugeValue,
				duration.Seconds(),
				task.TaskId,
				task.ClusterId,
				string(task.State),
			)
			log.Warn(ctx, "audit log task running or failed too long", zap.String("task_id", task.TaskId), zap.Time("create_at", task.CreatedAt))
		}
	}

	ch <- prometheus.MustNewConstMetric(
		AuditLogTaskCorruptedNumber,
		prometheus.GaugeValue,
		float64(corrupted),
	)
}
