package utils

import (
	"context"
	"sort"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
	"github.com/pingcap/errors"
	eksv1alpha1 "github.com/tidbcloud/eks-provider/api/v1alpha1"
)

func FetchEntryNode(ctx context.Context, cli client.Client, chaosWorkflow eksv1alpha1.ChaosWorkflow) ([]eksv1alpha1.ChaosWorkflowNode, error) {
	entryNodesList := v1alpha1.WorkflowNodeList{}
	controlledByWorkflow, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{
		MatchLabels: map[string]string{
			v1alpha1.LabelWorkflow: chaosWorkflow.Name,
		},
	})
	if err != nil {
		return nil, err
	}

	err = cli.List(ctx, &entryNodesList, &client.ListOptions{
		Namespace:     chaosWorkflow.Spec.RemoteNamespace,
		LabelSelector: controlledByWorkflow,
	})
	if err != nil {
		return nil, errors.Wrapf(err, "list entry workflow node")
	}

	sortedEntryNodes := SortByCreationTimestamp(entryNodesList.Items)
	sort.Sort(sortedEntryNodes)

	return ConvertToChaosWorkflowNodes(sortedEntryNodes, chaosWorkflow.Namespace), nil
}

type SortByCreationTimestamp []v1alpha1.WorkflowNode

func (it SortByCreationTimestamp) Len() int {
	return len(it)
}

func (it SortByCreationTimestamp) Less(i, j int) bool {
	return it[j].GetCreationTimestamp().After(it[i].GetCreationTimestamp().Time)
}

func (it SortByCreationTimestamp) Swap(i, j int) {
	it[i], it[j] = it[j], it[i]
}

func ConvertToChaosWorkflowNode(wfn v1alpha1.WorkflowNode, ns string) eksv1alpha1.ChaosWorkflowNode {
	node := eksv1alpha1.ChaosWorkflowNode{
		ObjectMeta: metav1.ObjectMeta{
			Name:      wfn.Name,
			Namespace: ns,
			Labels:    wfn.Labels,
		},
		Spec:   eksv1alpha1.ChaosWorkflowNodeSpec{WorkflowNodeSpec: wfn.Spec},
		Status: eksv1alpha1.ChaosWorkflowNodeStatus{WorkflowNodeStatus: wfn.Status},
	}

	return node
}

func ConvertToChaosWorkflowNodes(wfns []v1alpha1.WorkflowNode, ns string) []eksv1alpha1.ChaosWorkflowNode {
	chaosWorkflowNodes := make([]eksv1alpha1.ChaosWorkflowNode, 0, len(wfns))
	for _, wfn := range wfns {
		chaosWorkflowNodes = append(chaosWorkflowNodes, ConvertToChaosWorkflowNode(wfn, ns))
	}
	return chaosWorkflowNodes
}
