package api

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/dbaas/admin/forms"
	"github.com/pingcap/dbaas/admin/models"
	"github.com/pingcap/dbaas/central/model/billing"
)

// @Summary Update Global Discount
// @Tags Discount
// @Description Update global discount
// @Accept  json
// @Produce json
// @Param discount body forms.GlobalDiscount true "discount"
// @Success 200 {object} forms.GlobalDiscount
// @Router /global-discounts [put]
func UpdateGlobalDiscount(c *gin.Context) {
	req := forms.GlobalDiscount{}
	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	userContext := GetUserContext(c)

	err := userContext.BillingModel().UpdateGlobalOnDemandDiscount(req.Discount)
	if err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}
	Success(c, forms.GlobalDiscount{Discount: req.Discount}, http.StatusOK)
}

// @Summary Get Global Discount
// @Tags Discount
// @Description Update global discount
// @Accept  json
// @Produce json
// @Success 200 {object} forms.GlobalDiscount
// @Router /global-discounts [get]
func GetGlobalDiscount(c *gin.Context) {
	userContext := GetUserContext(c)

	result, err := userContext.BillingModel().GetGlobalOnDemandDiscount()
	if err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}
	Success(c, forms.GlobalDiscount{Discount: result}, http.StatusOK)
}

// @Summary Update Tenant Discount
// @Tags Discount
// @Description update discount
// @Accept  json
// @Produce json
// @Param org_id path string true "org_id"
// @Param discount body forms.Discount true "discount"
// @Success 200 {object} forms.Discount
// @Router /orgs/{org_id}/discounts [put]
func UpdateDiscount(c *gin.Context) {
	reqUri := forms.GetOrgIDReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	req := forms.Discount{}
	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	userContext := GetUserContext(c)
	err := userContext.BillingContext(reqUri.OrgID).UpdateTenantOnDemandDiscount(req.Discount)
	if err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}
	Success(c, forms.Discount{Discount: req.Discount}, http.StatusOK)
}

// @Summary Get Tenant Discount
// @Tags Discount
// @Description Get discount
// @Accept  json
// @Produce json
// @Param org_id path string true "org_id"
// @Success 200 {object} forms.Discount
// @Router /orgs/{org_id}/discounts [get]
func GetDiscount(c *gin.Context) {
	reqUri := forms.GetOrgIDReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	userContext := GetUserContext(c)

	result, err := userContext.BillingContext(reqUri.OrgID).GetTenantOnDemandDiscount()
	if err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}
	Success(c, forms.Discount{Discount: result}, http.StatusOK)
}

// @Summary Get Tenant Billing Status
// @Tags Billing
// @Description Get Tenant Billing Status
// @Accept  json
// @Produce json
// @Param org_id path string true "org_id"
// @Success 200 {object} forms.TenantRemaingCredits
// @Router /orgs/{org_id}/trial_credit [get]
func GetTrialCredit(c *gin.Context) {
	reqUri := forms.GetOrgIDReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	userContext := GetUserContext(c)
	result, err := userContext.BillingContext(reqUri.OrgID).GetPOCCredits()
	if err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}
	Success(c, forms.TenantRemaingCredits{RemainingCredit: result}, http.StatusOK)

}

// @Summary Add Trial Credit
// @tags Credit
// @Accept  json
// @Produce json
// @Param org_id path string  true "org_id"
// @Param user body forms.AddTrailCredit true "add trial credit"
// @Success 200 {object} forms.EmptyResponse
// @Router /orgs/{org_id}/trial_credit [post]
func AddTrialCredit(c *gin.Context) {
	reqUri := forms.GetOrgIDReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}
	req := forms.AddTrailCredit{}
	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	userContext := GetUserContext(c)
	trailCredit := billing.AddPOCCreditReq{
		TenantID:     reqUri.OrgID,
		CreditAmount: req.CreditAmount,
	}
	if err := userContext.BillingContext(reqUri.OrgID).AddPOCCredits(&trailCredit); err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	Success(c, nil, http.StatusOK)
}

// @Summary Update POC Status
// @tags poc
// @Accept  json
// @Produce json
// @Param org_id path string  true "org_id"
// @Param user body forms.UpdateOrgPocStatusReq true "update poc status"
// @Success 200 {object} forms.EmptyResponse
// @Router /orgs/{org_id}/poc [put]
func UpdateOrgPOCStatus(c *gin.Context) {
	reqUri := forms.GetOrgIDReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	req := forms.UpdateOrgPocStatusReq{}
	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}
	req.OrgID = reqUri.OrgID

	model := models.GetAdminModel()
	err := model.UpdateOrganizationPocStatus(c.Request.Context(), req)
	if err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	Success(c, nil, http.StatusOK)
}

// @Summary Get Tenant Credits History
// @Tags Billing
// @Description Tenant Credits History
// @Accept  json
// @Produce json
// @Param org_id path string true "org_id"
// @Success 200 {object} forms.TenantCreditsHistory
// @Router /orgs/{org_id}/credits_history [get]
func GetCreditsHistory(c *gin.Context) {
	reqUri := forms.GetOrgIDReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	userContext := GetUserContext(c)
	history, err := userContext.BillingContext(reqUri.OrgID).GetPOCCreditsHistory()
	if err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	res := forms.TenantCreditsHistory{
		Amount:  history.Amount,
		History: make([]forms.CreditsHistoryItem, len(history.History)),
	}

	for index := range history.History {
		res.History[index].Amount = history.History[index].Amount
		res.History[index].Created = history.History[index].Created
	}
	Success(c, res, http.StatusOK)

}

func RegisterBillingAPI(adminGroup gin.IRouter) {
	// discount
	adminGroup.PUT("/global-discounts", UpdateGlobalDiscount)
	adminGroup.GET("/global-discounts", GetGlobalDiscount)
	adminGroup.PUT("/orgs/:org_id/discounts", UpdateDiscount)
	adminGroup.GET("/orgs/:org_id/discounts", GetDiscount)

	adminGroup.POST("/orgs/:org_id/trial_credit", AddTrialCredit)
	adminGroup.GET("/orgs/:org_id/trial_credit", GetTrialCredit)
	adminGroup.PUT("/orgs/:org_id/poc", UpdateOrgPOCStatus)
	adminGroup.GET("/orgs/:org_id/credits_history", GetCreditsHistory)
}
