package jsmcli

import (
	"context"
	"crypto/sha256"
	"encoding/json"
	"fmt"

	"braces.dev/errtrace"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sqs"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"

	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/domain/adapter/jsm"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/pkg/config"
	eventutil "github.com/tidbcloud/tidb-management-service/utilities/clusterevent"
)

func NewClient(cfg *config.Jsm) jsm.Client {
	if cfg == nil || cfg.Local {
		return newFakeImpl()
	}

	return newClientImpl(cfg)
}

type clientImpl struct {
	enable    bool
	sqsRegion string
	sqsURL    string
	sqs       *sqs.SQS
}

func newClientImpl(cfg *config.Jsm) *clientImpl {
	if cfg == nil {
		return &clientImpl{
			enable: false,
		}
	}

	jsmC := &clientImpl{
		enable:    cfg.Enable,
		sqsRegion: cfg.SqsRegion,
		sqsURL:    cfg.SqsUrl,
	}
	if cfg.Enable {
		region := cfg.SqsRegion
		sess := session.Must(session.NewSessionWithOptions(session.Options{
			Config: aws.Config{
				Region: &region,
			},
			SharedConfigState: session.SharedConfigStateFromEnv,
		}))
		jsmC.sqs = sqs.New(sess)
		tilog.Info(context.Background(), "init jsm SQS client obj success", zap.String("region", region))
	}
	return jsmC
}

func (c *clientImpl) IsEnable() bool {
	return c.enable
}

type Message struct {
	Type             string           `json:"type"`
	ClusterInfoEvent ClusterInfoEvent `json:"cluster_info"`
}

type ClusterInfoEvent struct {
	ClusterID   uint64 `json:"cluster_id"`
	ProjectID   uint64 `json:"project_id"`
	OrgID       uint64 `json:"org_id"`
	DisplayName string `json:"display_name"`
	DeployType  string `json:"deploy_type"`
	ServicePlan string `json:"service_plan,omitempty"`
}

type MessageType string

const (
	MessageTypeCreateCluster MessageType = "create_cluster"
	MessageTypeDeleteCLuster MessageType = "delete_cluster"

	DedicatedDeployType  string = "dedicated"
	ServerlessDeployType string = "serverless"
	NextgenDeployType    string = "nextgen"
)

func (c *clientImpl) SendClusterEventToJsmSqs(
	ctx context.Context,
	cluster *eventutil.ClusterEvent,
	displayName string,
) error {
	if !c.enable {
		tilog.Info(ctx, "jsm client is not enable")
		return nil
	}
	clusterInfoEvent := ClusterInfoEvent{
		ClusterID:   cluster.ClusterID,
		ProjectID:   cluster.ProjectID,
		OrgID:       cluster.TenantID,
		DisplayName: displayName,
	}

	switch {
	case cluster.IsDevTier:
		clusterInfoEvent.DeployType = ServerlessDeployType
	case cluster.ServicePlan == "Premium" || cluster.ServicePlan == "BYOC":
		clusterInfoEvent.DeployType = NextgenDeployType
	default:
		clusterInfoEvent.DeployType = DedicatedDeployType
	}

	clusterInfoEvent.ServicePlan = cluster.ServicePlan

	var messageType MessageType
	switch cluster.EventType {
	case eventutil.EventTypeCreating:
		messageType = MessageTypeCreateCluster
	case eventutil.EventTypeDeleted:
		messageType = MessageTypeDeleteCLuster
	default:
		tilog.Error(ctx, "unknown cluster event type", zap.String("event type", string(cluster.EventType)))
		return nil
	}

	return errtrace.Wrap(
		c.sendSqsMessage(
			ctx,
			&Message{Type: string(messageType), ClusterInfoEvent: clusterInfoEvent},
			cluster.TenantID,
		),
	)
}

// sendSqsMessage
// use cluster org id for sqs group id
func (c *clientImpl) sendSqsMessage(ctx context.Context, m *Message, groupId uint64) error {
	data, _ := json.Marshal(m)
	message := string(data)
	sqsUrl := c.sqsURL
	sendParams := &sqs.SendMessageInput{
		MessageBody:            aws.String(message),
		QueueUrl:               aws.String(sqsUrl),
		MessageGroupId:         aws.String(fmt.Sprint(groupId)),
		MessageDeduplicationId: aws.String(fmt.Sprintf("%x", sha256.Sum256([]byte(message)))),
	}
	_, err := c.sqs.SendMessage(sendParams)
	if err != nil {
		return errtrace.Wrap(err)
	}
	tilog.Info(ctx, "succeed to send jsm sqs message.", zap.String("message", message))
	return nil
}
