package secondaryconfirm

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"

	"github.com/google/go-cmp/cmp"
	"github.com/tidbcloud/config-manager/pkg/clinic_event"
	"github.com/tidbcloud/pkgv2/goroutine"
	"sigs.k8s.io/controller-runtime/pkg/log"

	v1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/infra-provider/pkg/gitops-sdk/consts"
)

func SendApplyEvent(ctx context.Context, c *v1.Cluster, oldCr, cr *v1.ConfigRevision) error {
	logger := log.FromContext(ctx)
	// filter test cluster
	if _, err := strconv.ParseUint(c.Labels[v1.ClusterTagKey], 10, 64); err != nil {
		return fmt.Errorf("filter test cluster %s", c.Labels[v1.ClusterTagKey])
	}

	// filter v1/serveless cluster
	if c.Labels[v1.ProviderTypeLabel] != consts.ProviderTypeEKS && c.Labels[v1.ProviderTypeLabel] != consts.ProviderTypeGKE {
		return fmt.Errorf("filter aws/gcp/serverless cluster %s", c.Labels[v1.ProviderTypeLabel])
	}

	// filter init cluster
	if oldCr.Spec.Version == "" {
		return nil
	}

	name := fmt.Sprintf("%s-%s", clinic_event.EventNamePrefix, clinic_event.ActionApply)
	eventRequest := clinic_event.BuildGitopsEventTemplate(clinic_event.BuildContextID(cr.Name), name, c)

	// gen payload
	payloadByte, err := json.Marshal(cr.Spec)
	if err != nil {
		return err
	}
	payloadDecoder := json.NewDecoder(bytes.NewBuffer(payloadByte))
	payloadDecoder.UseNumber()
	_ = payloadDecoder.Decode(&eventRequest.Payload)

	eventRequest.Payload["diff"] = cmp.Diff(oldCr, cr)
	var summary string
	if oldCr.IsVersionChange(cr) {
		summary += fmt.Sprintf("upgrade tidb version to %s \n", cr.Spec.Version)
	}
	if components, ok := oldCr.IsImageChange(cr); ok {
		summary += fmt.Sprintf("patch components [%s] \n", joinComponents(components))
	}
	if components, ok := oldCr.IsConfigChange(cr); ok {
		summary += fmt.Sprintf("update [%s] configuration \n", joinComponents(components))
	}
	eventRequest.Payload["summary"] = summary
	goroutine.SafeGo(ctx, func() {
		if err := clinic_event.SendEvent(ctx, eventRequest); err != nil {
			logger.Error(err, "send event to clinic: %s", err)
		}
	})

	return nil
}

func joinComponents(components []v1.ComponentType) string {
	s := make([]string, 0, len(components))
	for _, c := range components {
		s = append(s, string(c))
	}
	return strings.Join(s, ", ")
}
