package dbuser

import (
	"context"
	"time"

	"github.com/pingcap/errors"

	"github.com/tidbcloud/account/internel/dao/entity"
	"gorm.io/gorm"
)

func (d *DBUserDao) CreateCommandDBUserCluster(ctx context.Context, tx *gorm.DB, clusterId uint64, orgId uint64, operator uint64, userId uint64, dbUser string, status entity.CommandStatus, action entity.CommandAction, targetType entity.ClusterUserTargetType, dbRole string, operatorType entity.ClusterUserTargetType) error {

	obj := &entity.CommandDBUserCluster{OrgID: entity.ID(orgId), Operator: entity.ID(operator), UserID: entity.ID(userId), ClusterID: entity.ID(clusterId), DbUser: dbUser, Status: status, Action: action, TargetType: targetType, DbRole: dbRole, OperatorType: operatorType}
	err := tx.Create(obj).Error
	if err != nil {
		return err
	}

	return nil
}

func (d *DBUserDao) BatchCreateCommandDBUserCluster(ctx context.Context, tx *gorm.DB, objs []entity.CommandDBUserCluster) error {

	err := tx.CreateInBatches(objs, len(objs)).Error
	if err != nil {
		return err
	}

	return nil
}

func (d *DBUserDao) CreateCommandDBUserClusterWithTime(ctx context.Context, tx *gorm.DB, clusterId uint64, orgId uint64, operator uint64, userId uint64, dbUser string, status entity.CommandStatus, action entity.CommandAction, targetType entity.ClusterUserTargetType, createTime time.Time, dbRole string, operatorType entity.ClusterUserTargetType) error {

	obj := &entity.CommandDBUserCluster{OrgID: entity.ID(orgId), Operator: entity.ID(operator), UserID: entity.ID(userId), ClusterID: entity.ID(clusterId), DbUser: dbUser, Status: status, Action: action, TargetType: targetType, DbRole: dbRole, OperatorType: operatorType}

	updatable := entity.Updatable{
		Base: entity.Base{
			CreatedAt: createTime,
		},
	}
	obj.Updatable = updatable

	err := tx.Create(obj).Error
	if err != nil {
		return err
	}

	return nil
}

func (d *DBUserDao) ListCommandDBUserClusters(ctx context.Context, tx *gorm.DB, filter CommandDBUserClusterFilter) ([]entity.CommandDBUserCluster, error) {
	var objs []entity.CommandDBUserCluster

	qs := entity.NewCommandDBUserClusterQuerySet(tx)

	if len(filter.IDs) > 0 {
		qs = qs.IDIn(filter.IDs...)
	}
	if len(filter.UserIDs) > 0 {
		qs = qs.UserIDIn(filter.OrgIDs...)
	}
	if len(filter.Operators) > 0 {
		qs = qs.OperatorIn(filter.Operators...)
	}
	if len(filter.OrgIDs) > 0 {
		qs = qs.OrgIDIn(filter.OrgIDs...)
	}
	if len(filter.ClusterIDS) > 0 {
		qs = qs.ClusterIDIn(filter.ClusterIDS...)
	}

	if len(filter.Status) > 0 {
		qs = qs.StatusIn(filter.Status...)
	}
	if len(filter.Actions) > 0 {
		qs = qs.ActionIn(filter.Actions...)
	}
	if filter.CreatedAtGte != nil {
		qs = qs.CreatedAtGte(*filter.CreatedAtGte)
	}

	qs = qs.OrderAscByCreatedAt()
	qs = qs.OrderAscByID()
	err := qs.All(&objs)
	if err != nil {
		return nil, err
	}
	//tilog.Info(ctx, "ListCommandDBUserClusters result", zap.Any("size", len(objs)))

	return objs, nil
}

func (d *DBUserDao) UpdateCommandDBUserCluster(ctx context.Context, tx *gorm.DB, c entity.CommandDBUserCluster) error {
	updater := entity.NewCommandDBUserClusterQuerySet(tx).IDEq(c.ID).GetUpdater()

	if c.Status != "" {
		updater.SetStatus(c.Status)
	}
	if c.Action != "" {
		updater.SetAction(c.Action)
	}
	if c.OrgID != 0 {
		updater.SetOrgID(c.OrgID)
	}
	if c.ClusterID != 0 {
		updater.SetClusterID(c.ClusterID)
	}
	if c.Operator != 0 {
		updater.SetOperator(c.Operator)
	}
	if c.UserID != 0 {
		updater.SetUserID(c.UserID)
	}
	if c.FailNum != 0 {
		updater.SetFailNum(c.FailNum)
	}
	if c.UpdatedAt != nil {
		updater.SetUpdatedAt(c.UpdatedAt)
	}

	err := updater.Update()

	if err != nil {
		return err
	}
	return nil
}

func (d *DBUserDao) DeleteCommandDBUserCluster(ctx context.Context, tx *gorm.DB, id uint64) error {
	err := entity.NewOrgKeyQuerySet(tx).IDEq(entity.ID(id)).Delete()

	if err != nil {
		return err
	}
	return nil
}

func (d *DBUserDao) UpdateCommandDBUserPushing(ctx context.Context, tx *gorm.DB, id uint64, to uint32) error {
	updater := entity.NewCommandDBUserClusterQuerySet(tx).IDEq(entity.ID(id)).GetUpdater()
	now := time.Now()
	err := updater.SetPushing(to).SetUpdatedAt(&now).Update()
	if err != nil {
		return err
	}
	return nil
}

func (d *DBUserDao) UpdateCommandDBUserPushingByFrom(ctx context.Context, tx *gorm.DB, id uint64, from, to uint32) error {
	updater := entity.NewCommandDBUserClusterQuerySet(tx).IDEq(entity.ID(id)).PushingEq(from).GetUpdater()
	now := time.Now()
	num, err := updater.SetPushing(to).SetUpdatedAt(&now).UpdateNum()
	if err != nil {
		return err
	}
	if num != 1 {
		return errors.New("not updated")
	}
	return nil
}
