package cluster_svc

import (
	"context"
	"strconv"
	"strings"
	"time"

	"github.com/shopspring/decimal"
	"github.com/tidbcloud/pkgv2/log"
	"github.com/tidbcloud/serverless-service/internal/config"
	"github.com/tidbcloud/serverless-service/internal/domain/entity"
	"github.com/tidbcloud/serverless-service/internal/domain/facade"
	"github.com/tidbcloud/serverless-service/internal/domain/repo"
	"go.uber.org/zap"
)

type DowntimeService struct {
	o11yFacade   facade.O11yFacade
	downtimeRepo repo.DowntimeRepo
}

func NewDowntimeService(
	o11yFacade facade.O11yFacade,
	downtimeRepo repo.DowntimeRepo,
) *DowntimeService {
	return &DowntimeService{
		o11yFacade:   o11yFacade,
		downtimeRepo: downtimeRepo,
	}
}

func (s *DowntimeService) Execute(ctx context.Context) error {
	logger := log.WithContextL(ctx).With(zap.String("job", "DowntimeService"))
	logger.Info("Execution Start")
	records := make([]*entity.Downtime, 0)
	for _, cfg := range config.Global().WorkerConfig.RegionalConfig {
		for _, k8sCfg := range cfg.K8sConfig {
			ilogger := logger.With(
				zap.String("provider", cfg.Provider),
				zap.String("region", cfg.Region),
				zap.String("kubernetes", k8sCfg.Kubernetes),
			)
			res, err := s.o11yFacade.GetDowntimes(ctx, k8sCfg.O11yUrl)
			if err != nil {
				ilogger.Error("failed to get o11y downtime metrics", zap.Error(err))
				continue
			}
			for k, v := range res {
				item := strings.Split(k, ":")
				if len(item) != 3 {
					ilogger.Error("failed to split key", zap.Any("key", k))
					continue
				}
				tm, err := strconv.ParseInt(item[1], 10, 64)
				if err != nil {
					ilogger.Error("failed to parser downtime data", zap.Error(err), zap.Any("result", k))
					continue
				}
				downTime := time.Unix(tm, 0)
				record := &entity.Downtime{
					ClusterID:   item[0],
					DownTime:    downTime,
					DownRate:    decimal.NewFromFloat(v.DownRate),
					Connections: decimal.NewFromFloat(v.Connections),
					Month:       downTime.Format("2006-01"),
					Region:      cfg.Provider + "/" + cfg.Region,
					TidbPool:    item[2],
				}
				records = append(records, record)
			}
		}
	}
	logger = logger.With(zap.Int("count", len(records)))
	if len(records) > 0 {
		if err := s.downtimeRepo.MultiSave(ctx, records); err != nil {
			logger.Error("failed to save rds", zap.Error(err), zap.Any("records", records))
		}
	} else {
		logger.Info("ignore empty downtime data.")
	}
	logger.Info("Execution End")
	return nil
}
