// Licensed Materials - Property of IBM
// (c) Copyright IBM Corporation 2018, 2019. All Rights Reserved.
// Note to U.S. Government Users Restricted Rights:
// Use, duplication or disclosure restricted by GSA ADP Schedule
// Contract with IBM Corp.
/* Copyright (c) 2020 Red Hat, Inc.
*/

package main

import (
	"flag"
	"os"
	"strings"

	"github.com/golang/glog"
	cs "github.com/open-cluster-management/hcm-compliance/pkg/client/clientset/versioned"
	"github.com/open-cluster-management/hcm-compliance/pkg/common"
	clientsetx "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
	"k8s.io/apimachinery/pkg/api/errors"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func main() {
	kubeconfig := flag.String("kubeconfig", "", "Path to a kube config. Only required if out-of-cluster.")
	namespace := flag.String("namespace", v1.NamespaceAll, "Kubernestes namespace")
	removelist := flag.String("removelist", "", "Comma separated list of crds to remove - e.g. compliances,policies")
	flag.Parse()

	if *removelist == "" {
		glog.Errorf("The list of crds to remove is empty")
		os.Exit(1)
	}

	// create a map with the options
	crds := make(map[string]bool)
	items := strings.Split(*removelist, ",")
	for _, item := range items {
		crds[item] = true
	}

	glog.V(3).Infof("Starting uninstall crds...")

	// build config for local cluster
	lConfig, err := common.BuildConfig(kubeconfig)
	if err != nil {
		panic(err)
	}

	defer glog.Flush()

	// create the clientset for the crd resources
	client, err := cs.NewForConfig(lConfig)
	if err != nil {
		panic(err)
	}

	// create the api ext client for the crd resources
	crdx, err := clientsetx.NewForConfig(lConfig)
	if err != nil {
		panic(err)
	}

	// handle compliances
	if _, ok := crds["compliances"]; ok {
		compls, err := client.ComplianceV1alpha1().Compliances(*namespace).List(v1.ListOptions{})
		if err != nil { // crd is likely not installed
			glog.Warning(err)
		} else { // crd is installed, try to cleanup
			for _, comp := range compls.Items {
				glog.V(5).Infof("Found %s", comp.SelfLink)
				// remove all finalizers
				comp = *comp.DeepCopy()
				comp.SetFinalizers([]string{})
				_, err = client.ComplianceV1alpha1().Compliances(comp.Namespace).Update(&comp)
				if err != nil {
					glog.Warning(err)
				}
			}
			// now get rid of the crd
			crdx.Apiextensions().CustomResourceDefinitions().Delete("compliances.compliance.mcm.ibm.com", &v1.DeleteOptions{})
		}
	}

	// handle policies
	if _, ok := crds["policies"]; ok {
		pols, err := client.PolicyV1alpha1().Policies(*namespace).List(v1.ListOptions{})
		if err != nil { // crd is likely not installed
			glog.Warning(err)
		} else { // crd is installed, try to cleanup
			for _, pol := range pols.Items {
				glog.V(5).Infof("Found %s", pol.SelfLink)
				// remove all finalizers
				pol = *pol.DeepCopy()
				pol.SetFinalizers([]string{})
				_, err = client.PolicyV1alpha1().Policies(pol.Namespace).Update(&pol)
				if err != nil {
					glog.Warning(err)
				}
			}
		}
		// now get rid of the crd
		err = crdx.Apiextensions().CustomResourceDefinitions().Delete("policies.policy.mcm.ibm.com", &v1.DeleteOptions{})
		if err != nil {
			if errors.IsNotFound(err) {
				// policies.policy.mcm.ibm.com CRD not found, deletion was successful
				glog.Info(err)
			} else {
				panic(err)
			}
		}
	}

	// handle accesspolicies
	if _, ok := crds["accesspolicies"]; ok {
		apols, err := client.AccesspolicyV1alpha1().AccessPolicies(*namespace).List(v1.ListOptions{})
		if err != nil { // crd is likely not installed
			glog.Warning(err)
		} else { // crd is installed, try to cleanup
			for _, apol := range apols.Items {
				glog.V(5).Infof("Found %s", apol.SelfLink)
				// remove all finalizers
				apol = *apol.DeepCopy()
				apol.SetFinalizers([]string{})
				_, err = client.AccesspolicyV1alpha1().AccessPolicies(apol.Namespace).Update(&apol)
				if err != nil {
					glog.Warning(err)
				}
			}
			// now get rid of the crd
			crdx.Apiextensions().CustomResourceDefinitions().Delete("accesspolicies.accesspolicy.mcm.ibm.com", &v1.DeleteOptions{})
		}
	}
}
