package clusteranomalydetection

import (
	"context"
	"fmt"
	"strconv"
	"strings"

	"github.com/tidbcloud/devops/entity/message"
	"github.com/tidbcloud/devops/pkg/infra/clients/cliniccli"
	"github.com/tidbcloud/devops/pkg/infra/clients/coresvccli"
	"github.com/tidbcloud/devops/pkg/infra/config"
	"github.com/tidbcloud/devops/pkg/infra/consts"
	"github.com/tidbcloud/devops/pkg/infra/log"
	msgapi "github.com/tidbcloud/devops/pkg/service/message/api"
)

type ClusterAnomalyDetection struct {
	msgSvc    msgapi.MessageServiceAPI
	conf      config.ClusterAnomalyDetectionConfig
	cliniccli cliniccli.Client
	coreSvc   coresvccli.CoreSvcCli
}

func NewClusterAnomalyDetection(
	msgSvc msgapi.MessageServiceAPI,
	conf config.ClusterAnomalyDetectionConfig,
	clinicCli cliniccli.Client,
	coreSvc coresvccli.CoreSvcCli,
) (*ClusterAnomalyDetection, error) {

	return &ClusterAnomalyDetection{
		msgSvc:    msgSvc,
		conf:      conf,
		cliniccli: clinicCli,
		coreSvc:   coreSvc,
	}, nil
}

func (d *ClusterAnomalyDetection) DetectAndNotify(ctx context.Context) error {
	totalText := make([]string, 0)
	// generate all detections' texts
	for _, clusterIDStr := range d.conf.ClusterIDs {
		clusterID, err := strconv.ParseUint(clusterIDStr, 10, 64)
		if err != nil {
			log.FromContext(ctx).Error(err, "parse cluster id", "cluster id", clusterIDStr)
			continue
		}
		clusters, err := d.cliniccli.ListClusters(ctx, &cliniccli.ClusterFilter{ClusterIds: []string{clusterIDStr}})
		if err != nil {
			log.FromContext(ctx).Error(err, "get cluster info", "cluster id", clusterID)
			continue
		}
		if len(clusters) == 0 {
			log.FromContext(ctx).Error(fmt.Errorf("cluster is not found in clinic"), "error msg", "cluster id", clusterID)
			continue
		}
		cluster := clusters[0]

		if d.conf.LongUnfinishedSQL != nil {
			text, err := d.GenerateLongUnfinishedSQLNotifyText(
				ctx,
				&TopSQLDetectionReq{
					ClusterID: clusterIDStr,
					OrgID:     cluster.OrgID,
					Duration:  d.conf.LongUnfinishedSQL.Duration,
				})
			if err != nil {
				log.FromContext(ctx).Error(err, "generate top sql notify text", "cluster id", clusterID)
				continue
			}
			if text != "" {
				text = fmt.Sprintf("Cluster Name: %s (ID: %s)\n%s", cluster.ClusterName, clusterIDStr, text)
				totalText = append(totalText, text)
			}
		}
	}

	// combine all the texts and send notification
	finalText := ""
	for _, text := range totalText {
		finalText += text + "\n\n"
	}

	emailBodyVars := map[string]string{
		"body": finalText,
	}

	if finalText != "" {
		log.FromContext(ctx).Info("generated final text", "text", finalText)
		err := d.msgSvc.SendEmail(ctx, msgapi.SendEmailParam{
			Name: fmt.Sprintf("Cluster Anomaly Detection Notification for Clusters: %s", strings.Join(d.conf.ClusterIDs, ", ")),
			Target: message.EmailTarget{
				Users: &message.EmailTargetUsers{
					Emails: d.conf.ReceiverEmails,
				},
			},
			Template: message.EmailTemplate{
				ID:        d.conf.TemplateID,
				Variables: emailBodyVars,
			},
			Reason:      "send cluster anomaly detection email",
			Applicant:   consts.InternalVirtualEmail,
			FromAddress: d.conf.EmailFromAddress,
			CCAdresses:  d.conf.CC,
			BCCAdresses: d.conf.BCC,
		})
		if err != nil {
			log.FromContext(ctx).Error(err, "send cluster anomaly detection email")
			return err
		}
	}

	return nil
}
