package api

import (
	"errors"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/dbaas/billing2/billing_errors"
	"github.com/pingcap/dbaas/billing2/constant"
	"github.com/pingcap/dbaas/billing2/db/entity"
	"github.com/pingcap/dbaas/billing2/model/billingconfig"
	"github.com/pingcap/dbaas/billing2/model/costexplorer"
	"github.com/pingcap/dbaas/billing2/utils/ginutils"
	"github.com/pingcap/dbaas/billing2/utils/timeutils"
)

type MspMonthlyCostURI struct {
	TenantID      uint   `uri:"tenant_id" binding:"required"`
	BilledMonth   string `uri:"billedMonth" binding:"required"`
	MspCustomerId uint   `uri:"mspCustomerId"`
}

// @Tags MSP
// @Summary Return monthly bills for a specific MSP customer
// @Description  This endpoint retrieves the bill for the given month of a specific end customer of MSP. You can query a bill up to 6 months prior to the current month. The bill is returned in JSON format.
// @Schemes
// @Accept json
// @Produce json
// @Param billedMonth path string true "The month of this bill happens for the specified organization. The format is YYYY-MM, for example, '2023-08'."
// @Param mspCustomerId path string true "ID of the MSP customer."
// @Success 200 {object} forms.BillsExplorer
// @Failure 400  {object}  billing_errors.BaseError
// @Router /mspCustomerBills/{billedMonth}/mspCustomers/{mspCustomerId}  [GET]
func (s *API) BillsExplorerByMspCustomerOpenAPI(c *gin.Context) (ginutils.HandlerFuncResult, error) {

	query := &MspMonthlyCostURI{}
	err := c.ShouldBindUri(query)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}

	billedMonth, err := time.Parse("2006-01", query.BilledMonth)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	now := time.Now()
	startMonth := timeutils.GetMonthDate(now).AddDate(0, constant.QueryBillsMonthLimit, 0)
	if billedMonth.Before(startMonth) || billedMonth.After(now) {
		return nil, billing_errors.NewInvalidInputError(errors.New("param billedMonth is invalid. You can query a bill up to 6 months prior to the current month"))

	}
	models := &billingconfig.BillingConfigModel{}
	billingConfigID, err := models.GetActiveBillingConfigID(query.MspCustomerId)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	paymentMethod, err := paymentModel.GetActivePaymentMethod(query.MspCustomerId, billingConfigID)

	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}

	if paymentMethod.PaymentType != entity.PaymentType_MSP || paymentMethod.PaymentCode != strconv.FormatUint(uint64(query.TenantID), 10) {
		return nil, billing_errors.NewInvalidInputError(errors.New("param mspCustomerId is invalid"))
	}

	model := &costexplorer.CostExplorerModel{}
	return model.CalculateMspCustomerOpenAPIMonthlyCostWithCache(query.MspCustomerId, billingConfigID, billedMonth)

}

// @Tags MSP
// @Summary Return MSP monthly bills
// @Description  This endpoint retrieves the bill for the given month of a specific MSP. You can query a bill up to 6 months prior to the current month. The bill is returned in JSON format.
// @Schemes
// @Accept json
// @Produce json
// @Param billedMonth path string true "The month of this bill happens for the specified organization. The format is YYYY-MM, for example, '2023-08'."
// @Success 200 {object} forms.MspBills
// @Failure 400  {object}  billing_errors.BaseError
// @Failure 403  {object}  billing_errors.BaseError
// @Router /bills/{billedMonth} [GET]
func (s *API) MspBillsExplorerOpenAPI(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	query := &MspMonthlyCostURI{}
	err := c.ShouldBindUri(query)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	models := &billingconfig.BillingConfigModel{}
	isMsp, err := models.IsMspWithCache(query.TenantID)
	if !isMsp {
		return nil, billing_errors.NewActionForbiddenError(errors.New("The API requires an MSP API key."))
	}

	billedMonth, err := time.Parse("2006-01", query.BilledMonth)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	now := timeutils.GetNow()
	startMonth := timeutils.GetMonthDate(now).AddDate(0, constant.QueryBillsMonthLimit, 0)
	if billedMonth.Before(startMonth) || billedMonth.After(now) {
		return nil, billing_errors.NewInvalidInputError(errors.New("Param billedMonth is invalid. You can query a bill up to 6 months prior to the current month."))

	}

	model := &costexplorer.CostExplorerModel{}
	return model.CalculateMspOpenAPIMonthlyCostWithCache(query.TenantID, billedMonth)

}

func InitializeMspOpenAPICostExplorerRouter(router ginutils.MyRoute) {
	s := &API{}

	router.HandleWithError("GET", "/tenants/:tenant_id/mspCustomerBills/:billedMonth/mspCustomers/:mspCustomerId", s.BillsExplorerByMspCustomerOpenAPI)
	router.HandleWithError("GET", "/mspCustomerBills/:billedMonth/mspCustomers/:mspCustomerId", s.BillsExplorerByMspCustomerOpenAPI)
	router.HandleWithError("GET", "/tenants/:tenant_id/bills/:billedMonth", s.MspBillsExplorerOpenAPI)
	router.HandleWithError("GET", "/bills/:billedMonth", s.MspBillsExplorerOpenAPI)
}
