package awscrossplane

import (
	"context"
	"fmt"

	ec2v1alpha1 "github.com/crossplane-contrib/provider-aws/apis/ec2/v1alpha1"
	xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

// FindReusableVPCEndpointName tries to find a reusable vpc endpoint, so we do not need to create a new one.
// The reusable vpc endpoint should have the same service name and vpc id as given.
func FindReusableVPCEndpointName(ctx context.Context, cli client.Client, endpointType, endpointServiceName, vpcID string) (string, error) {
	endpointList := &ec2v1alpha1.VPCEndpointList{}
	err := cli.List(ctx, endpointList)
	if err != nil {
		return "", fmt.Errorf("failed to list vpc endpoint: %w", err)
	}
	for i, endpoint := range endpointList.Items {
		if isVPCEndpointReusable(&endpoint, endpointType, endpointServiceName, vpcID) {
			return endpointList.Items[i].Name, nil
		}
	}
	return "", nil
}

// isVPCEndpointReusable checks whether the given vpc endpoint is reusable.
// A reusable vpc endpoint should have the same service name and vpc id as given,
// and should not be in deleting state.
func isVPCEndpointReusable(endpoint *ec2v1alpha1.VPCEndpoint, endpointType, serviceName, vpcID string) bool {
	if endpoint.Spec.ForProvider.ServiceName == nil || *endpoint.Spec.ForProvider.ServiceName != serviceName {
		return false
	}
	if endpoint.Spec.ForProvider.VPCID == nil || *endpoint.Spec.ForProvider.VPCID != vpcID {
		return false
	}
	if endpoint.Spec.ForProvider.VPCEndpointType == nil || *endpoint.Spec.ForProvider.VPCEndpointType != endpointType {
		return false
	}
	// Check if not in deleting state
	condition := endpoint.Status.GetCondition(xpv1.TypeReady)
	if condition.Reason == xpv1.ReasonDeleting {
		return false
	}
	return true
}

// GetVPCEndpointDNSByEndpointName retrieves the DNS name from VPC Endpoint status
// using the given endpoint name.
// It returns an error if the VPC Endpoint is not found or has no DNS entries.
func GetVPCEndpointDNSByEndpointName(ctx context.Context, cli client.Client, endpointName string) (string, error) {
	ep := &ec2v1alpha1.VPCEndpoint{}
	ep.Name = endpointName
	if err := cli.Get(ctx, client.ObjectKeyFromObject(ep), ep); err != nil {
		return "", fmt.Errorf("failed to get vpc endpoint: %w", err)
	}

	if len(ep.Status.AtProvider.DNSEntries) > 0 {
		for _, entry := range ep.Status.AtProvider.DNSEntries {
			if entry.DNSName != nil {
				return *entry.DNSName, nil
			}
		}
	}

	return "", fmt.Errorf("no DNS entries found in vpc endpoint status")
}
