package api

import (
	"github.com/gin-gonic/gin"
	"github.com/pingcap/dbaas/billing2/billing_errors"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/handler/centralhandler"
	"github.com/pingcap/dbaas/billing2/model/billingconfig"
	"github.com/pingcap/dbaas/billing2/utils/log"
	"github.com/tidbcloud/tiinf/sdk/auth"
	"go.uber.org/zap"
)

type TenantIDStruct struct {
	TenantID uint `uri:"tenant_id" binding:"required"`
}
type BillingConfigIDStruct struct {
	BillingConfigID uint `uri:"billing_config_id"`
}
type BillingCfgStruct struct {
	TenantIDStruct
	BillingConfigID uint `uri:"billing_config_id"`
}

func getTenantIDFromURI(c *gin.Context) (uint, error) {
	tenantIDStruct := &TenantIDStruct{}
	err := c.ShouldBindUri(tenantIDStruct)
	if err != nil {
		return 0, billing_errors.NewInvalidInputError(err)
	}
	return tenantIDStruct.TenantID, nil
}

func getBillingConfigIDFromURI(c *gin.Context) (uint, error) {
	billingCfgStruct := &BillingCfgStruct{}
	err := c.ShouldBindUri(billingCfgStruct)
	if err != nil {
		return 0, billing_errors.NewInvalidInputError(err)
	}
	if billingCfgStruct.BillingConfigID == 0 {
		model := &billingconfig.BillingConfigModel{}
		billingConfigID, err := model.GetActiveBillingConfigID(billingCfgStruct.TenantID)
		if err != nil {
			return 0, billing_errors.NewInvalidInputError(err)
		}
		billingCfgStruct.BillingConfigID = billingConfigID
	}
	return billingCfgStruct.BillingConfigID, nil
}

func getBillingCfgFromURI(c *gin.Context) (*forms.BillingConfig, error) {
	billingCfgStruct := &BillingCfgStruct{}
	err := c.ShouldBindUri(billingCfgStruct)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	var ret *forms.BillingConfig
	model := &billingconfig.BillingConfigModel{}
	if billingCfgStruct.BillingConfigID == 0 {
		ret, err = model.GetActiveBillingConfig(billingCfgStruct.TenantID)
		if err != nil {
			return nil, billing_errors.NewInvalidInputError(err)
		}
	} else {
		ret, err = model.GetBillingConfig(billingCfgStruct.BillingConfigID)
		if err != nil {
			return nil, err
		}
		if ret.TenantID != billingCfgStruct.TenantID {
			log.Error("unmatched billing config and tenant id", zap.Uint("tenantID", billingCfgStruct.TenantID), zap.Uint("billingConfigID", billingCfgStruct.BillingConfigID))
			return nil, billing_errors.ObjectNotExistsError
		}
	}
	return ret, nil
}

func getBillingCfgFromAuth(c *gin.Context) (*forms.BillingConfig, error) {
	authInfo, err := auth.GetIdentityInfoFromGinContext(c)
	if err != nil {
		return nil, err
	}
	model := &billingconfig.BillingConfigModel{}
	billingConfig, err := model.GetActiveBillingConfig(uint(authInfo.OrgID))
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	return billingConfig, nil
}

func getCustomerIDFromUri(c *gin.Context, partnerID uint) (uint, error) {
	var query struct {
		CustomerId uint `uri:"customerId"  binding:"required"`
	}
	err := c.ShouldBindUri(&query)
	if err != nil {
		return 0, err
	}
	isPartnersCustomer, err := centralhandler.GetCentralHandler().IsPartnersCustomer(partnerID, query.CustomerId)
	if err != nil {
		return 0, err
	}
	if !isPartnersCustomer {
		log.Info("the customer is not managed by the partner", zap.Uint("customerID", query.CustomerId), zap.Uint("partnerID", partnerID))
		return 0, billing_errors.NewObjectNotExistsError(nil)
	}
	return query.CustomerId, nil
}
