package privatelinkservicemigration

import (
	"context"
	"fmt"

	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"

	globaldedicatedv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/dedicated/v1"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/service/workflow/common"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func (svc *service) Cancel(ctx context.Context, req *globaldedicatedv1.CancelPrivateLinkServiceMigrationRequest) error {
	_, span := tracer.Start(ctx, "Domain.CancelPrivateLinkServiceMigrationSvc")
	defer span.End()

	if err := svc.transaction.Transaction(ctx, func(ctx context.Context) error {
		migration, err := svc.privatelinkservicemigrationRepo.Get(ctx, req.GetId())
		if err != nil {
			return err
		}

		// if migration is succeeded or cancelled, return error
		if migration.State == globaldedicatedv1.PrivateLinkServiceMigration_SUCCEEDED ||
			migration.State == globaldedicatedv1.PrivateLinkServiceMigration_CANCELLED {
			return bizerr.New(bizerr.ErrCodeParams, "migration is already succeeded or cancelled")
		}

		for _, mtg := range migration.GetMigrationTidbGroups() {
			if mtg.State != globaldedicatedv1.PrivateLinkServiceMigration_SUCCEEDED &&
				mtg.State != globaldedicatedv1.PrivateLinkServiceMigration_CANCELLED {
				mtg.State = globaldedicatedv1.PrivateLinkServiceMigration_CANCELLED
				mtg.Message = "Migration cancelled"
				_, err = svc.privatelinkservicemigrationRepo.UpdateMigrationTidbGroup(ctx, migration.Id, mtg)
				if err != nil {
					return err
				}
			}
		}

		migration.State = globaldedicatedv1.PrivateLinkServiceMigration_CANCELLED
		migration.Message = "Migration cancelled"
		_, err = svc.privatelinkservicemigrationRepo.UpdateState(
			ctx,
			migration.Id,
			globaldedicatedv1.PrivateLinkServiceMigration_CANCELLED,
			"Migration cancelled",
		)
		if err != nil {
			tilog.Error(
				ctx,
				"failed to update migration state",
				zap.Error(err),
				zap.String("migration_id", fmt.Sprintf("%d", migration.Id)),
			)
			return err
		}

		// delete the migration workflow dag instance
		err = svc.workflow.DeleteDagInstancesWithDagId(ctx, fmt.Sprintf("%d", migration.Id), common.CutoverPrivateLinkService)
		if err != nil {
			tilog.Error(
				ctx,
				"failed to delete migration workflow dag instance",
				zap.Error(err),
				zap.String("migration_id", fmt.Sprintf("%d", migration.Id)),
			)
			return err
		}
		// delete the poll private link service migration status workflow dag instance
		err = svc.workflow.DeleteDagInstancesWithDagId(ctx, fmt.Sprintf("%d", migration.Id), common.PollPrivateLinkServiceMigrationStatus)
		if err != nil {
			tilog.Error(
				ctx,
				"failed to delete poll private link service migration status workflow dag instance",
				zap.Error(err),
				zap.String("migration_id", fmt.Sprintf("%d", migration.Id)),
			)
			return err
		}
		tilog.Info(
			ctx,
			"deleted migration workflow dag instance",
			zap.String("migration_id", fmt.Sprintf("%d", migration.Id)),
		)
		return nil
	}); err != nil {
		return err
	}
	return nil
}
