package task

import (
	"context"
	"fmt"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"gopkg.in/yaml.v3"

	k8sent "github.com/tidbcloud/devops/entity/k8supgrade"
	"github.com/tidbcloud/devops/pkg/infra/errs"
	"github.com/tidbcloud/devops/pkg/infra/log"
	"github.com/tidbcloud/devops/pkg/service/k8supgrade/infrainfo"
	"github.com/tidbcloud/devops/pkg/service/k8supgrade/task/utils"
)

const (
	uoStatusDeleted  = "Deleted"
	uoStatusPaused   = "Paused"
	uoStatusNotFound = "NotFound"
	uoStatusNone     = "None"
)

// syncCanceledTask syncs a cancelled task.
// It closes the maintenance window and pause/delete the UpgradeOperation CR for each k8s cluster.
func (s *svc) syncCanceledTask(ctx context.Context, taskID uint64) {
	logger := log.FromContext(ctx, "func", "syncCanceledTask")

	k8sClusters, err := s.taskRepo.ListK8sClusters(ctx, taskID, false)
	if err != nil {
		logger.Error(err, "failed to list k8s clusters for task", "task_id", taskID)
		return
	}

	// TODO: use goroutines to speed up the process
	for _, cluster := range k8sClusters {
		if err = utils.CloseMaintenanceWindowByID(ctx, s.maintenanceWindowSvc, cluster.MaintenanceWindowID); err != nil {
			logger.Error(err, "failed to close the maintenance window", "k8s", cluster.Name)
		}

		if err = s.pauseOrDeleteUpgradeOperation(ctx, cluster); err != nil {
			logger.Error(err, "failed to pause or delete the UpgradeOperation CR", "k8s", cluster.Name)
		}
	}
}

func (s *svc) pauseOrDeleteUpgradeOperation(ctx context.Context, cluster *k8sent.K8sCluster) error {
	if len(cluster.UpgradeOperationCR) == 0 {
		cluster.UpgradeOperationStatus = uoStatusNotFound
		return nil
	}

	var uoEntity k8sent.UpgradeOperation
	if err := yaml.Unmarshal([]byte(cluster.UpgradeOperationCR), &uoEntity); err != nil {
		return fmt.Errorf("fail to unmarshal the UpgradeOperation CR: %w", err)
	}

	req := &infrainfo.CommonUpgradeOperationReq{
		Namespace:     uoEntity.Namespace,
		Name:          uoEntity.Name,
		CloudProvider: cluster.CloudProvider,
		Region:        cluster.Region,
	}
	currentUO, err := s.infraInfoSvc.GetUpgradeOperation(ctx, req)
	if err != nil {
		if errs.IsNotFound(err) {
			cluster.UpgradeOperationStatus = uoStatusNotFound
			return nil
		}
		return fmt.Errorf("fail to get UpgradeOperation CR: %w", err)
	}

	if currentUO.Status == nil {
		cluster.UpgradeOperationStatus = uoStatusNone
		return nil
	}

	switch currentUO.Status.Phase {
	case string(cloudv1.UpgradeOperationPhaseNone), string(cloudv1.UpgradeOperationPhasePending):
		if err = s.infraInfoSvc.DeleteUpgradeOperation(ctx, req); err != nil {
			return fmt.Errorf("fail to delete the UpgradeOperation CR: %w", err)
		}
		cluster.UpgradeOperationStatus = uoStatusDeleted

	case string(cloudv1.UpgradeOperationPhaseRunning):
		if err = s.infraInfoSvc.PauseUpgradeOperation(ctx, req); err != nil {
			return fmt.Errorf("fail to pause UpgradeOperation CR: %w", err)
		}
		cluster.UpgradeOperationStatus = uoStatusPaused
	}
	return nil
}
