package internal

import (
	"os"

	"github.com/juju/errors"
	log "github.com/sirupsen/logrus"
	"k8s.io/client-go/tools/clientcmd"

	"github.com/tidbcloud/auto-deploy/internal/argocd"
	cloud_provider "github.com/tidbcloud/auto-deploy/internal/cloud-provider"
	"github.com/tidbcloud/auto-deploy/internal/constants"
	global_client "github.com/tidbcloud/auto-deploy/internal/global-client"
	"github.com/tidbcloud/auto-deploy/internal/job"
	"github.com/tidbcloud/auto-deploy/internal/meta"
	oidc_provider "github.com/tidbcloud/auto-deploy/internal/oidc-provider"
	"github.com/tidbcloud/auto-deploy/internal/types"
	"github.com/tidbcloud/auto-deploy/internal/utils"
)

type DestroyAwsRegionK8sArgs struct {
	OidcProviderType types.OidcProviderType
	InstanceName     string
	RegionName       string
	Region           string
	MetaURI          string
	RoleArn          string
	DeployType       string
}

func DestroyAwsRegionK8s(args DestroyAwsRegionK8sArgs) error {
	logger := log.WithFields(log.Fields{
		"instance": args.InstanceName,
		"name":     args.RegionName,
		"meta-uri": args.MetaURI,
	})

	account, err := types.FromAwsArn(args.RoleArn)
	if err != nil {
		return err
	}
	oidcProvider, err := oidc_provider.GetProvider(args.OidcProviderType)
	if err != nil {
		return err
	}
	logger.WithField("oidc-provider", args.OidcProviderType).Debug("Get load oidc provider")
	cloudProvider, err := cloud_provider.NewAWSCloudProvider(oidcProvider, *account, args.Region)
	if err != nil {
		return err
	}
	logger.WithField("account", account.AwsRole.AccountId).Debug("Auth to AWS")

	homeDir, err := os.UserHomeDir()
	if err != nil {
		return errors.Annotatef(err, "Failed to get home dir")
	}
	cloudProvider.WriteToLocal(homeDir, []types.Account{})
	logger.WithField("home-dir", homeDir).Info("Write temp credential files to host")

	logger.Debug("Start to destory aws region k8s")
	region, err := meta.LoadRegionControl(args.MetaURI, args.InstanceName, args.RegionName)
	if err != nil {
		return err
	}
	logger.Debug("Loaded region meta")

	if region.Region != args.Region {
		return errors.BadRequestf("Region not match with meta %s != %s", region.Region, args.Region)
	}

	if region.CloudProviderType != types.AWS {
		return errors.BadRequestf("Region cloud provider is not %s", types.AWS)
	}

	cloudProvider.WriteToLocal(homeDir, region.TidbClusterAccounts)
	logger.WithField("home-dir", homeDir).Info("Write credential files to host")

	region.CloudProvider = cloudProvider
	region.OidcProvider = oidcProvider
	region.LatestRunId = oidcProvider.GetRunID()
	region.K8s.CredentialSecretName = constants.AWS_SECRET_NAME
	region.K8s.CredentialSecret = cloudProvider.GetAuthConfigYaml(constants.AWS_SECRET_NAME, region.TidbClusterAccounts)

	err = CheckRegionResource(region)
	if err != nil {
		return err
	}

	err = job.RunFinalizerJobs(region)
	if err != nil {
		return err
	}

	err = argocd.UnregisterK8s(&region.K8s)
	if err != nil {
		return err
	}

	err = cloudProvider.DestroyK8s(&region.K8s)
	if err != nil {
		logger.WithField("error", err).Error("Failed to destroy aws region k8s")
		return err
	}

	region.JobOutputs = make(map[string]types.JobOutput)
	logger.Info("Finished to destroy aws region k8s")
	err = meta.SaveRegionControl(args.MetaURI, *region)
	if err != nil {
		region.Print()
		return err
	}

	authKey := os.Getenv(constants.GLOBAL_AUTH_KEY_ENV)
	client := global_client.NewGlobalClient(region.GlobalOptions.Env, authKey, global_client.DEFAULT_TIMEOUT, log.IsLevelEnabled(log.DebugLevel))
	if args.DeployType == global_client.DEPLOY_TYPE_NEXTGEN {
		err := client.DeleteRegionalConfigCenter(region.GlobalOptions.LogicalRegionName)
		if err != nil {
			logger.WithError(err).Error("Failed to register regional config center")
		}
	}
	return client.DeleteRegionById(args.DeployType, region.GlobalOptions.LogicalRegionName, region.CloudProviderType)
}

func CheckRegionResource(region *types.Region) error {
	kubeconfig, err := region.CloudProvider.GetKubeConfig(&region.K8s)
	if err != nil {
		return err
	}
	config, err := clientcmd.RESTConfigFromKubeConfig([]byte(kubeconfig))
	if err != nil {
		return errors.Annotatef(err, "Failed to load kubeconfig: %s", kubeconfig)
	}
	hasResource, err := utils.CheckResources([]string{"infra-api", "regionserver", "providerconfigusages"}, config)
	if err != nil {
		return errors.Annotate(err, "Failed to get managed resource")
	}
	if hasResource {
		return errors.Forbiddenf("Finalizer job")
	}
	return nil
}
