package wait

import (
	"context"
	"fmt"
	"time"

	"sigs.k8s.io/controller-runtime/pkg/client"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/shared-provider/pkg/types"
	"github.com/tidbcloud/shared-provider/pkg/utils/labels"
)

func WaitForNetworkPhase(
	ctx context.Context,
	c client.Client,
	net *cloudv1.Network,
	phase string,
	timeout time.Duration,
) error {
	cond := func() bool {
		return net.Status.Phase == phase
	}

	if err := WaitForCondition(ctx, c, net, cond, timeout); err != nil {
		return fmt.Errorf("network phase is not %s: %w", phase, err)
	}

	return nil
}

func WaitForNetworkRescheduleFailed(
	ctx context.Context,
	c client.Client,
	net *cloudv1.Network,
	reason string,
	timeout time.Duration,
) error {
	cond := func() bool {
		val, ok := net.Annotations[types.AnnoKeyRescheduleFailedReason]
		if !ok {
			return false
		}
		if reason == "" || reason == val {
			return true
		}
		return false
	}

	if err := WaitForCondition(ctx, c, net, cond, timeout); err != nil {
		if reason == "" {
			return fmt.Errorf("network reschedule is not failed: %w", err)
		}
		return fmt.Errorf("network reschedule is not failed with reason %s: %w", reason, err)
	}

	return nil
}

func WaitForNetworkRescheduled(
	ctx context.Context,
	c client.Client,
	net *cloudv1.Network,
	to string,
	timeout time.Duration,
) error {
	cond := func() bool {
		if _, ok := net.Annotations[types.AnnoKeyRescheduleFailedReason]; ok {
			return false
		}
		if _, ok := net.Annotations[types.AnnoKeyReschedule]; ok {
			return false
		}
		val, ok := net.Labels[labels.LabelKeyKubernetesCluster]
		if !ok {
			return false
		}
		if val != to {
			return false
		}
		// DON'T check kubernetes label, it may have been set by dispatcher
		return true
	}

	if err := WaitForCondition(ctx, c, net, cond, timeout); err != nil {
		return fmt.Errorf("network is not rescheduled: %w", err)
	}

	return nil
}
