package api

import (
	"errors"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/dbaas/billing2/billing_errors"
	"github.com/pingcap/dbaas/billing2/db/entity"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/model/marketing"
	"github.com/pingcap/dbaas/billing2/utils/ginutils"
	"github.com/pingcap/dbaas/billing2/utils/timeutils"
	"github.com/shopspring/decimal"
)

type RechargePlanAPI struct{}

type RechargePlanIDStruct struct {
	RechargePlanID uint `uri:"recharge_plan_id" binding:"required"`
}

func getRechargePlanIDFromURI(c *gin.Context) (uint, error) {
	query := &RechargePlanIDStruct{}
	err := c.ShouldBindUri(query)
	if err != nil {
		return 0, billing_errors.NewInvalidInputError(err)
	}
	return query.RechargePlanID, nil
}

type TenantRechargePlanIDStruct struct {
	TenantID             uint `uri:"tenant_id" binding:"required"`
	TenantRechargePlanID uint `uri:"tenant_recharge_plan_id" binding:"required"`
}

func getTenantRechargePlanIDFromURI(c *gin.Context) (*TenantRechargePlanIDStruct, error) {
	query := &TenantRechargePlanIDStruct{}
	err := c.ShouldBindUri(query)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	return query, nil
}

// @Summary List Recharge Plans
// @Schemes
// @Description List Recharge Plans
// @Accept  json
// @Produce json
// @Success 200 {object} []forms.RechargeCreditsPlan
// @Router /recharge_plans [get]
func (s *RechargePlanAPI) ListRechargePlans(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	result, err := (&marketing.RechargeCreditsModel{}).ListWebRechargePlans()
	if err != nil {
		return nil, err
	}
	return result, nil
}

// @Summary Get Recharge Plan Info
// @Schemes
// @Description Get Recharge Plan Info
// @Accept  json
// @Produce json
// @Param recharge_plan_id path string true "recharge_plan_id"
// @Success 200 {object} forms.RechargeCreditsPlan
// @Router /recharge_plans/{recharge_plan_id} [get]
func (s *RechargePlanAPI) GetRechargePlan(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	recharge_plan_id, err := getRechargePlanIDFromURI(c)
	if err != nil {
		return nil, err
	}
	result, err := (&marketing.RechargeCreditsModel{}).GetRechargePlan(recharge_plan_id)
	if err != nil {
		return nil, err
	}
	return result, nil
}

// @Summary Create Recharge Plan
// @Schemes
// @Description Create Recharge Plan
// @Accept  json
// @Produce json
// @Param recharge_plan body forms.RechargeCreditsPlanInput true "recharge_plan"
// @Success 200 {object} forms.RechargeCreditsPlan
// @Router /recharge_plans/{recharge_plan_id} [post]
func (s *RechargePlanAPI) CreateRechargePlan(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	query := &forms.RechargeCreditsPlan{}
	err := c.ShouldBindJSON(query)
	if err != nil {
		return nil, err
	}
	if query.Value.LessThanOrEqual(decimal.Zero) {
		return nil, billing_errors.NewInvalidInputError(errors.New("value must be positive"))
	}
	query.Duration = 99 * 365 * 24 * time.Hour
	query.StartDate = timeutils.GetNow()
	query.ExpiredDate = time.Date(2099, 12, 31, 0, 0, 0, 0, time.UTC)
	query.Source = entity.RechargeCreditsPlanSource_Web
	result, err := (&marketing.RechargeCreditsModel{}).CreateRechargePlan(query)
	if err != nil {
		return nil, err
	}
	return result, nil
}

// @Summary Update Recharge Plan Value
// @Schemes
// @Description Update Recharge Plan Value
// @Accept  json
// @Produce json
// @Param recharge_plan_id path string true "recharge_plan_id"
// @Param value body decimal.Decimal true "value"
// @Success 200 {object} forms.RechargeCreditsPlan
// @Router /recharge_plans/{recharge_plan_id} [patch]
func (s *RechargePlanAPI) UpdateRechargePlanValue(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	recharge_plan_id, err := getRechargePlanIDFromURI(c)
	if err != nil {
		return nil, err
	}
	query := &forms.RechargeCreditsPlan{}
	err = c.ShouldBindJSON(query)
	if err != nil {
		return nil, err
	}
	if query.Value.LessThanOrEqual(decimal.Zero) {
		return nil, billing_errors.NewInvalidInputError(errors.New("value must be positive"))
	}
	ret, err := (&marketing.RechargeCreditsModel{}).UpdateRechargePlanValue(recharge_plan_id, query.Value)
	if err != nil {
		return nil, err
	}
	return ret, nil
}

// @Summary Disable Recharge Plan
// @Schemes
// @Description Disable Recharge Plan
// @Accept  json
// @Produce json
// @Param recharge_plan_id path string true "recharge_plan_id"
// @Success 200 {object} forms.OKType
// @Router /recharge_plans/{recharge_plan_id} [delete]
func (s *RechargePlanAPI) DisableRechargePlan(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	recharge_plan_id, err := getRechargePlanIDFromURI(c)
	if err != nil {
		return nil, err
	}
	err = (&marketing.RechargeCreditsModel{}).DisableRechargePlan(recharge_plan_id)
	if err != nil {
		return nil, err
	}
	return forms.OK, nil
}

// @Summary Get Tenant Recharge Plan Info
// @Schemes
// @Description Get Recharge Plan Info
// @Accept  json
// @Produce json
// @Param tenant_recharge_plan_id path string true "tenant_recharge_plan_id"
// @Success 200 {object} forms.TenantRechargeCreditsPlan
// @Router /tenants/{tenant_id}/recharge_plans/{tenant_recharge_plan_id} [get]
func (s *RechargePlanAPI) GetTenantRechargePlan(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	query, err := getTenantRechargePlanIDFromURI(c)
	if err != nil {
		return nil, err
	}
	result, err := (&marketing.RechargeCreditsModel{}).GetTenantRechargePlan(query.TenantRechargePlanID)
	if err != nil {
		return nil, err
	}
	if result.TenantID != query.TenantRechargePlanID {
		return nil, billing_errors.ObjectNotExistsError
	}
	return result, nil
}

// @Summary Disable Tenant Recharge Plan
// @Schemes
// @Description Disable Recharge Plan
// @Accept  json
// @Produce json
// @Param tenant_recharge_plan_id path string true "tenant_recharge_plan_id"
// @Success 200 {object} forms.OKType
// @Router /tenants/{tenant_id}/recharge_plans/{tenant_recharge_plan_id} [delete]
func (s *RechargePlanAPI) DisableTenantRechargePlan(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	tenant_recharge_plan, err := s.GetTenantRechargePlan(c)
	if err != nil {
		return nil, err
	}
	err = (&marketing.RechargeCreditsModel{}).DisableTenantRechargePlan(tenant_recharge_plan.(*forms.TenantRechargeCreditsPlan).PlanID)
	if err != nil {
		return nil, err
	}
	return forms.OK, nil
}

func InitializeRechargePlanRouter(router ginutils.MyRoute) {
	s := &RechargePlanAPI{}
	router.HandleWithError("POST", "/recharge_plans", s.CreateRechargePlan)
	router.HandleWithError("GET", "/recharge_plans", s.ListRechargePlans)
	router.HandleWithError("GET", "/recharge_plans/:recharge_plan_id", s.GetRechargePlan)
	router.HandleWithError("PATCH", "/recharge_plans/:recharge_plan_id", s.UpdateRechargePlanValue)
	router.HandleWithError("DELETE", "/recharge_plans/:recharge_plan_id", s.DisableRechargePlan)
	router.HandleWithError("GET", "/tenants/:tenant_id/recharge_plans/:tenant_recharge_plan_id", s.GetTenantRechargePlan)
	router.HandleWithError("DELETE", "/tenants/:tenant_id/recharge_plans/:tenant_recharge_plan_id", s.DisableTenantRechargePlan)

}
