package api

import (
	"fmt"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"github.com/pingcap/dbaas/billing2/billing_errors"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/model/billing"
	"github.com/pingcap/dbaas/billing2/model/marketing/discount"
	"github.com/pingcap/dbaas/billing2/model/marketing/plan"
	"github.com/pingcap/dbaas/billing2/utils/ginutils"
	"github.com/pingcap/dbaas/billing2/utils/timeutils"
	"github.com/pingcap/dbaas/billing2/workers"
)

// @Summary Worker Run Action
// @Schemes
// @Accept json
// @Produce json
// @Param WorkerAction body forms.WorkerTaskAction true "WorkerTaskAction"
// @Success 200 {object} forms.OKType
// @Router /worker/run [post]
func (s *API) WorkerRunAction(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	workerAction := &forms.WorkerTaskAction{}
	if err := c.ShouldBindJSON(workerAction); err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	timeutils.SetNowFunc(func() time.Time {
		return workerAction.RunTime
	})
	var err error
	switch workerAction.Action {
	case "support_plan_metering":
		err = workers.SendSupportPlanMetering()
	case "credits":
		workers.CloseExhaustedCreditsPackage()
		workers.CloseExpiredCreditsPackage()
		workers.OpenNeedOpenCreditsPackage()
	case "merge_small_costs":
		err = workers.MergeSmallCosts()
	case "remove_unused_costs":
		err = workers.RemoveUnusedCosts()
	case "remove_unused_raw_costs":
		err = workers.RemoveUnusedRawCosts()
	case "mark_merged_costs_to_raw":
		err = workers.MarkMergedCostsToRaw()
	case "credit_tenant_close":
		err = workers.ProgressTenantCreditRiskClose()
	case "poc_sync_credits":
		err = workers.POCSyncCredits()
	case "poc_cleanup":
		err = workers.POCCleanup()
	case "poc_credits_email_reminder":
		err = workers.POCCreditsEmailReminder()
	case "support_plan_free_trial_reminder":
		err = workers.SendSupportPlanFreeTrialReminder()
	case "invoice_worker":
		workers.CreateInvoiceWorker()
	case "spend_limit":
		err = workers.CheckAllSpendLimit()
	case "inactive_timeout_discount":
		err = workers.InactiveTimeoutDiscountWorker()
	case "inactive_timeout_binded_packages":
		err = workers.InactiveTimeoutBindedPackagesWorker()
	case "sync_payable":
		err = workers.SyncTenantPayableWorker()
	case "cost_quota_invoice":
		err = workers.CreateCostQuotaInvoice()
	case "reconciliation_daily":
		err = workers.ReconciliationDailyWorker()
	case "reconciliation_monthly":
		err = workers.ReconciliationMonthlyWorker()
	case "generate_aws_reconciliation_report":
		err = workers.GenerateAWSDailyReportWorker()
	case "cost_explorer_cache":
		workers.CostExplorerCacheWorker()
	case "ar_estimated":
		err = workers.AREstimatedWorker()
	case "ar_actual":
		err = workers.ARActualWorker()
	case "s3_bills_detail":
		workers.S3BillsDetailExportWorker()
	case "lake_cloud_service_fee":
		err = workers.RunLakeCloudServiceFee()
	default:
		return nil, billing_errors.NewInvalidInputError(fmt.Errorf("unknown worker action %s", workerAction.Action))
	}
	if err != nil {
		return nil, err
	}
	return forms.OK, nil
}

// @Summary Worker Run Action
// @Schemes
// @Accept json
// @Produce json
// @Param WorkerAction body forms.WorkerSubTaskAction true "WorkerSubTaskAction"
// @Success 200 {object} forms.OKType
// @Router /worker/subtask/run [post]
func (s *API) RunWorkerSubTask(c *gin.Context) (ginutils.HandlerFuncResult, error) {
	workerAction := &forms.WorkerSubTaskAction{}
	var err error
	if err := c.ShouldBindJSON(workerAction); err != nil {
		return nil, billing_errors.NewInvalidInputError(err)
	}
	timeutils.SetNowFunc(func() time.Time {
		return workerAction.RunTime
	})
	planModel := &plan.TenantPlanModel{}
	switch workerAction.Action {
	case "support_plan_metering":
		workers.SupportPlanWorkerByTenant(workerAction.TenantID)
	case "poc_sync_credits":
		err = planModel.SyncPOCCreditsSalesforce(workerAction.TenantID)
	case "poc_cleanup":
		err = planModel.POCCleanup(workerAction.TenantID)
	case "poc_credits_email_reminder":
		err = planModel.SendPOCReminderEmail(workerAction.TenantID)
	case "invoice_worker":
		workers.CreateInvoiceWorkerByTenant(workerAction.TenantID)
	case "spend_limit":
		workers.CheckSpendLimitByTenant(workerAction.TenantID)
	case "inactive_timeout_discount":
		_, err = (&discount.Model{}).InactiveTimeoutDiscount(workerAction.TenantID)
	case "inactive_timeout_binded_packages":
		_, err = (&billing.BindedPackageModel{}).InactiveTimeoutBindedPackages(workerAction.TenantID)
	case "recharge":
		workers.RechargeByTenant(workerAction.TenantID)
	case "sync_payable":
		err = paymentModel.SyncPayable(workerAction.TenantID)
	case "merge_small_costs":
		err = workers.MergeSmallCosts(workerAction.TenantID)
	case "remove_unused_costs":
		err = workers.RemoveUnusedCosts(workerAction.TenantID)
	case "remove_unused_raw_costs":
		err = workers.RemoveUnusedRawCosts(workerAction.TenantID)
	case "mark_merged_costs_to_raw":
		err = workers.MarkMergedCostsToRaw(workerAction.TenantID)
	case "cost_quota_invoice":
		workers.CreateCostQuotaInvoiceByTenant(workerAction.TenantID)
	case "lake_cloud_service_fee":
		workers.RunLakeCloudServiceFeeByTenant(uuid.NewString(), workerAction.TenantID)
	default:
		return nil, billing_errors.NewInvalidInputError(fmt.Errorf("unknown worker action %s", workerAction.Action))
	}

	if err != nil {
		return nil, err
	}
	return forms.OK, nil
}

func InitializeWorkerRunActionRouter(router ginutils.MyRoute) {
	api := &API{}
	router.HandleWithError("POST", "/worker/run", api.WorkerRunAction)
	router.HandleWithError("POST", "/worker/subtask/run", api.RunWorkerSubTask)
}
