package worker

import (
	"context"
	"fmt"
	"time"

	"github.com/juju/errors"
	"github.com/pingcap/dbaas/central/config"
	"github.com/pingcap/dbaas/central/db/entity"
	"github.com/pingcap/dbaas/central/model/util"
	"go.uber.org/zap"
)

func (c BgContext) DisableOrgDevTier() error {
	ctx := context.Background()
	tx := c.GetDB()
	enabled, err := c.IsOrgDevTierEnabled()
	if err != nil {
		return err
	}

	if !enabled {
		return errors.New("dev tier is not enabled.")
	}

	trial, err := c.GetDevTierEntity()
	if err != nil {
		return err
	}
	now := time.Now()

	trial.EndedAt = &now
	err = trial.Update(tx, entity.TrialDBSchema.EndedAt)
	if err != nil {
		c.Log().Error("failed to end trail record")
		return errors.Trace(err)
	}

	t, err := c.GetTenantEntity()
	if err != nil {
		return err
	}

	notificationMgr := util.NewNotificationMgr()

	user, err := c.GetAdminUser(t.Email)
	if err != nil {
		return err
	}

	identifier := fmt.Sprintf("%d:%s", trial.ID, entity.DevTierTrialStageEnd)

	err = notificationMgr.SendNotificationOnce(ctx, tx, trial.TenantID, entity.NotificationSceneDevTierTrial, identifier, func() error {
		vars := map[string]string{
			"userName": user.FirstName,
		}
		return c.GetMailHandler().SendMailWithTemplate(ctx, []string{user.Email}, config.EmailSubjectDevTierTrialEnd, config.TNDevTierTrialEnd, vars, nil)
	})

	if err != nil {
		c.Log().Error("failed to send dev tier end email", zap.Error(err))
		return err
	}

	clusterContext, err := c.clusterModel.BgContext(c.GetTenantID())
	if err != nil {
		c.Log().Error("failed get cluster bg context", zap.Error(err))
		return err
	}
	err = clusterContext.CleanFreeClusters(ctx)
	if err != nil {
		c.Log().Error("failed clean clusters", zap.Error(err))
		return err
	}
	return nil
}

func (c BgContext) DisableOutdatedDevTier() error {
	enabled, err := c.IsOrgDevTierEnabled()
	if err != nil {
		return err
	}
	if !enabled {
		c.Log().Info("the dev tier is not enabled.")
		return nil
	}

	stage, err := c.GetDevTierStage(time.Now())
	if err != nil {
		c.Log().Error("failed to get dev tier stage", zap.Error(err))
		return err
	}

	if stage == entity.DevTierTrialStageEnd {
		err = c.DisableOrgDevTier()
		if err != nil {
			c.Log().Error("failed to disable dev tier", zap.Error(err))
			return err
		}
	}
	return nil
}

const (
	dateFormat = "2006-01-02"
)

func (c BgContext) NotifyUserDevTierStage() error {
	enabled, err := c.IsOrgDevTierEnabled()
	if err != nil {
		return err
	}
	if !enabled {
		c.Log().Info("the dev tier is not enabled.")
		return nil
	}

	stage, err := c.GetDevTierStage(time.Now())
	if err != nil {
		c.Log().Error("failed to get dev tier stage", zap.Error(err))
		return err
	}

	t, err := c.GetTenantEntity()
	if err != nil {
		return err
	}

	user, err := c.GetAdminUser(t.Email)
	if err != nil {
		return err
	}

	tx := c.GetDB()

	trial, err := c.GetDevTierEntity()

	if err != nil {
		return err
	}

	// identifier: trial.ID + stage
	identifier := fmt.Sprintf("%d:%s", trial.ID, stage)
	notificationMgr := util.NewNotificationMgr()

	ctx := context.Background()

	ddl := trial.EstimatedEndedAt

	err = notificationMgr.SendNotificationOnce(ctx, tx, trial.TenantID, entity.NotificationSceneDevTierTrial, identifier, func() error {
		switch stage {
		case entity.DevTierTrialStageCloseToEndStage1:
			vars := map[string]string{
				"userName":     user.FirstName,
				"shutdownDate": ddl.Format(dateFormat),
			}
			return c.GetMailHandler().SendMailWithTemplate(ctx, []string{user.Email}, config.EmailSubjectDevTierTrialCloseToEndEmailStage1, config.TNDevTierTrialCloseToEndStage1, vars, nil)
		case entity.DevTierTrialStageCloseToEndStage2:
			vars := map[string]string{
				"userName":     user.FirstName,
				"shutdownDate": ddl.Format(dateFormat),
			}
			return c.GetMailHandler().SendMailWithTemplate(ctx, []string{user.Email}, config.EmailSubjectDevTierTrialCloseToEndEmailStage2, config.TNDevTierTrialCloseToEndStage2, vars, nil)
		default:
			return nil
		}
	})
	return errors.Annotate(err, "send dev tier trial close to end notification")
}
