package api

import (
	"errors"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/dbaas/billing2/billing_errors"
	"github.com/pingcap/dbaas/billing2/db"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/model/migrate"
	"github.com/pingcap/dbaas/billing2/utils/ginutils"
	"github.com/pingcap/dbaas/billing2/utils/log"
	"go.uber.org/zap"
)

type migrateTaskAPI struct{}

type MigrateTaskQuery struct {
	Name string `uri:"name" binding:"required"`
}

// @Summary Run Async Migrate Task
// @Schemes
// @Accept json
// @Produce json
// @Param name path string true "name"
// @Success 200 {object} forms.OKType
// @Router /migrate_tasks/{name} [post]
func (s *migrateTaskAPI) RunMigrateTask(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	query := MigrateTaskQuery{}
	err := c.ShouldBindUri(&query)
	if err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	migrateModel := migrate.MigrateModel{}
	var f func() error
	switch query.Name {
	case "update_stripe_email":
		f = migrateModel.UpdateStripeEmail
	case "recal":
		args := struct {
			Start int64 `json:"start"`
			End   int64 `json:"end"`
		}{}
		err = c.ShouldBindJSON(&args)
		if err != nil {
			return nil, err
		}
		f = func() error {
			return migrateModel.ReCalculateMeasures(db.GetDB(), args.Start, args.End)
		}
	case "create_recal_invoice":
		args := struct {
			TenantIDs []uint    `json:"tenant_ids"`
			Date      time.Time `json:"date"`
		}{}
		err = c.ShouldBindJSON(&args)
		if err != nil {
			return nil, err
		}
		f = func() error {
			return migrateModel.CreateReCalculateInvoices(args.Date, args.TenantIDs)
		}
	case "spend_limit_recharge_plan_id_migration":
		f = migrateModel.MigrateSpendLimitRechargePlanID
	case "create_billing_config":
		f = migrateModel.CreateAllTenantIDBillingConfig
	case "create_novu_subscribers":
		f = migrateModel.CreateAllTenantIDNovuSubscriber
	case "sync_binded_support_plans_to_eventbus":
		f = migrateModel.SyncAllSupportPlanInfoToEventBus
	case "sync_on_demand_orgs_to_jsm":
		f = migrateModel.SyncOnDemandOrgsToJSM
	default:
		return nil, billing_errors.NewInvalidInputError(errors.New("unknown task name"))
	}
	go func() {
		log.Info("start to run migrate task", zap.String("name", query.Name))
		err = f()
		if err != nil {
			log.Error("failed to run migrate task", zap.Error(err), zap.String("name", query.Name))
		}
		log.Info("success to run migrate task", zap.String("name", query.Name))
	}()
	return forms.OK, nil
}

func InitializeMigrateRouter(router ginutils.MyRoute) {
	s := &migrateTaskAPI{}
	router.HandleWithError("POST", "/migrate_tasks/:name", s.RunMigrateTask)

}
