package jsm

import (
	"encoding/json"
	"fmt"

	"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/google/uuid"
	"github.com/pingcap/dbaas/billing2/config"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/utils/log"
	"go.uber.org/zap"
)

type SupportMessage struct {
	TenantID uint   `json:"tenant_id"`
	Level    string `json:"level"`
}

type OnDemandMessage struct {
	TenantID uint `json:"tenant_id"`
	OnDemand bool `json:"on_demand"`
}

func supportMsgFromBindedSupportPlan(support *forms.BindedSupportPlan) (string, error) {
	msg := &SupportMessage{
		TenantID: support.TenantID,
		Level:    support.Level,
	}
	ret, err := json.Marshal(msg)
	if err != nil {
		return "", err
	}
	return string(ret), nil
}

func NewJSMSQSClient() (*sqs.SQS, error) {
	sess, err := session.NewSession()
	if err != nil {
		return nil, err
	}
	region := config.Get().GetString(config.JSMSQSRegion)
	sess = sess.Copy(&aws.Config{Region: &region})
	sqsClient := sqs.New(sess)
	return sqsClient, nil
}

func SendJSMSupport(support *forms.BindedSupportPlan) {
	if !config.Get().GetBool(config.JSMEnableSender) {
		log.Info("cancel to send support info to jsm", zap.Uint("tenantID", support.TenantID), zap.String("level", support.Level))
		return
	}
	log.Info("start to send support info to jsm", zap.Uint("tenantID", support.TenantID), zap.String("level", support.Level))
	msg, err := supportMsgFromBindedSupportPlan(support)
	if err != nil {
		log.Error("failed to marshall msg", zap.Error(err), zap.Uint("tenantID", support.TenantID), zap.String("level", support.Level))
		return
	}
	sqsClient, err := NewJSMSQSClient()
	if err != nil {
		log.Error("failed to init jsm sqs client", zap.Error(err), zap.Uint("tenantID", support.TenantID), zap.String("level", support.Level))
		return
	}
	queue := config.Get().GetString(config.JSMSQSQueue)
	params := &sqs.SendMessageInput{
		MessageBody:            aws.String(msg),
		QueueUrl:               aws.String(queue),
		MessageGroupId:         aws.String(fmt.Sprint(support.TenantID)),
		MessageDeduplicationId: aws.String(uuid.NewString()),
	}
	ret, err := sqsClient.SendMessage(params)
	if err != nil {
		log.Error("failed to send jsm msg to sqs", zap.Error(err), zap.Uint("tenantID", support.TenantID), zap.String("level", support.Level))
		return
	}
	log.Info("success to send jsm msg to sqs", zap.Error(err), zap.Uint("tenantID", support.TenantID), zap.String("level", support.Level), zap.String("messages", *ret.MessageId))
}

func SyncOnDemandInfoToJSM(tenantID uint, onDemand bool) {
	if !config.Get().GetBool(config.SyncOnDemandOrgToJSMEnable) {
		log.Info("Forbidden to sync on-demand org to jsm")
		return
	}
	log.Info("start to sync on-demand org to jsm", zap.Uint("tenantID", tenantID), zap.Bool("onDemand", onDemand))
	sqsClient, err := NewJSMSQSClient()
	if err != nil {
		log.Error("failed to sync on-demand org to jsm, init jsm sqs error", zap.Uint("tenantID", tenantID), zap.Bool("onDemand", onDemand), zap.Error(err))
		return
	}
	msg, err := json.Marshal(&OnDemandMessage{
		TenantID: tenantID,
		OnDemand: onDemand,
	})
	if err != nil {
		log.Error("failed to sync on-demand org to jsm, json marshal error", zap.Uint("tenantID", tenantID), zap.Bool("onDemand", onDemand), zap.Error(err))
		return
	}
	queue := config.Get().GetString(config.JSMSQSQueue)
	params := &sqs.SendMessageInput{
		MessageBody:            aws.String(string(msg)),
		QueueUrl:               aws.String(queue),
		MessageGroupId:         aws.String(fmt.Sprint(tenantID)),
		MessageDeduplicationId: aws.String(uuid.NewString()),
	}
	ret, err := sqsClient.SendMessage(params)
	if err != nil {
		log.Error("failed to sync on-demand org to jsm", zap.Uint("tenantID", tenantID), zap.Error(err))
		return
	}
	log.Info("success to sync on-demand org to jsm", zap.Uint("tenantID", tenantID), zap.Bool("onDemand", onDemand), zap.String("messages", *ret.MessageId))
}
