package aliyunsubscriptionmngt

import (
	"errors"

	"github.com/pingcap/dbaas/billing2/billing_errors"
	"github.com/pingcap/dbaas/billing2/db"
	"github.com/pingcap/dbaas/billing2/db/entity"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/utils/log"
	"go.uber.org/zap"
)

type AliyunSubscriptionMngt struct{}

func isThirdPartyProductCode(productCode string) bool {
	return productCode != "" && productCode != "sgcmgj00035763" && productCode != "sgcmgj00035199"
}

func subscriptionRecordFromEntity(subscription *entity.AliyunSubscriptionManagement) *forms.AliyunSubscriptionRecord {
	return &forms.AliyunSubscriptionRecord{
		AliUid:       subscription.AliUid,
		BizId:        subscription.BizId,
		IsSubscribed: subscription.IsSubscribed,
		InTrial:      subscription.InTrial,
		ProductCode:  subscription.ProductCode,
		IsThirdParty: subscription.IsThirdParty,
	}
}

func (s *AliyunSubscriptionMngt) CreateOrActiveSubscriptionRecord(record *forms.AliyunSubscriptionRecord) (*forms.AliyunSubscriptionRecord, error) {
	var entityRecord entity.AliyunSubscriptionManagement
	err := entity.NewAliyunSubscriptionManagementQuerySet(db.GetDB()).BizIdEq(record.BizId).One(&entityRecord)
	if err != nil {
		if errors.Is(err, billing_errors.ObjectNotExistsError) {
			record.IsThirdParty = isThirdPartyProductCode(record.ProductCode)
			err = (&entity.AliyunSubscriptionManagement{
				AliUid:       record.AliUid,
				BizId:        record.BizId,
				InTrial:      record.InTrial,
				IsSubscribed: true,
				ProductCode:  record.ProductCode,
				IsThirdParty: record.IsThirdParty,
			}).Create(db.GetDB())
			if err != nil {
				log.Error("Error creating aliyun subscription record", zap.Error(err))
				return nil, err
			}
			return record, nil
		}
		log.Error("Error querying aliyun subscription record", zap.Error(err))
		return nil, err
	}
	log.Info("Aliyun subscription record already exists", zap.Any("record", record))
	if !entityRecord.IsSubscribed {
		err = entity.NewAliyunSubscriptionManagementQuerySet(db.GetDB()).BizIdEq(record.BizId).GetUpdater().SetIsSubscribed(true).Update()
		if err != nil {
			log.Error("Error active aliyun subscription", zap.String("bizId", record.BizId), zap.Error(err))
			return nil, err
		}

	}
	return record, nil
}

func (s *AliyunSubscriptionMngt) InActiveSubscriptionRecordWithBizId(bizId string) (*forms.AliyunSubscriptionRecord, error) {
	var subscription entity.AliyunSubscriptionManagement
	err := entity.NewAliyunSubscriptionManagementQuerySet(db.GetDB()).BizIdEq(bizId).One(&subscription)
	if err != nil {
		log.Error("Error querying aliyun subscription record", zap.String("bizId", bizId), zap.Error(err))
		return nil, err
	}
	if !subscription.IsSubscribed {
		log.Info("Aliyun subscription record already unsubscribed", zap.Any("record", subscription))
		return subscriptionRecordFromEntity(&subscription), nil
	}
	err = entity.NewAliyunSubscriptionManagementQuerySet(db.GetDB()).BizIdEq(bizId).GetUpdater().SetIsSubscribed(false).Update()
	if err != nil {
		log.Error("inactive aliyun subscription", zap.String("bizId", bizId), zap.Error(err))
		return nil, err
	}
	result := subscriptionRecordFromEntity(&subscription)
	result.IsSubscribed = false
	return result, nil
}

func (s *AliyunSubscriptionMngt) GetActiveSubscriptionRecordByAliUid(aliUid string) (*forms.AliyunSubscriptionRecord, error) {
	var subscription entity.AliyunSubscriptionManagement
	err := entity.NewAliyunSubscriptionManagementQuerySet(db.GetDB()).AliUidEq(aliUid).IsSubscribedEq(true).OrderDescByCreatedAt().One(&subscription)
	if err != nil {
		return nil, err
	}
	return subscriptionRecordFromEntity(&subscription), nil
}

func (s *AliyunSubscriptionMngt) GetLastSubscriptionRecodByAliUid(aliUid string) (*forms.AliyunSubscriptionRecord, error) {
	var subscription entity.AliyunSubscriptionManagement
	err := entity.NewAliyunSubscriptionManagementQuerySet(db.GetDB()).AliUidEq(aliUid).OrderDescByCreatedAt().One(&subscription)
	if err != nil {
		log.Error("Error querying aliyun subscription record", zap.String("aliUid", aliUid), zap.Error(err))
		return nil, err
	}
	return subscriptionRecordFromEntity(&subscription), nil
}

func (s *AliyunSubscriptionMngt) GetSubscriptionRecordByBizId(bizId string) (*forms.AliyunSubscriptionRecord, error) {
	var subscription entity.AliyunSubscriptionManagement
	err := entity.NewAliyunSubscriptionManagementQuerySet(db.GetDB()).BizIdEq(bizId).One(&subscription)
	if err != nil {
		log.Error("Error querying aliyun subscription record", zap.String("bizId", bizId), zap.Error(err))
		return nil, err
	}
	return subscriptionRecordFromEntity(&subscription), nil
}

func (s *AliyunSubscriptionMngt) GetSubscriptionRecordByTenantId(tenantID uint) (*forms.AliyunSubscriptionRecord, error) {
	var paymentMethod entity.PaymentMethod
	err := entity.NewPaymentMethodQuerySet(db.GetDB()).
		TenantIDEq(tenantID).
		PaymentTypeEq(entity.PaymentType_AliCloud).
		StatusEq(entity.PaymentMethodStatus_Active).
		One(&paymentMethod)
	if err != nil {
		log.Error("Error querying payment method by tenant id", zap.Uint("tenantId", tenantID), zap.Error(err))
		return nil, err
	}
	return s.GetLastSubscriptionRecodByAliUid(paymentMethod.PaymentCode)
}
