package message

import (
	"errors"
	"net"

	regionalapiv1 "github.com/tidbcloud/cluster-service-ng/api/tidbcloud/dataplane-manager/v1"
)

type CreatePrivateLinkServiceReqValidatable struct {
	*regionalapiv1.CreatePrivateLinkServiceRequest
}

func (c *CreatePrivateLinkServiceReqValidatable) Validate() error {
	if c == nil {
		return errors.New("request is nil")
	}
	if c.PrivateLinkService == nil {
		return errors.New("PrivateLinkService is nil")
	}
	if c.Id == "" {
		return errors.New("Id is empty")
	}

	for _, conn := range c.PrivateLinkService.GetConnections() {
		if conn.GetInfo() == nil {
			return errors.New("PrivateLinkService.Connections.Info is nil")
		}
		switch conn.GetInfo().(type) {
		case *regionalapiv1.PrivateLinkService_Connection_Aws_:
			if conn.GetAws() == nil {
				return errors.New("PrivateLinkService.Connections.Aws is nil")
			}
			if conn.GetAws().GetVpcEndpointId() == "" {
				return errors.New("PrivateLinkService.Connections.Aws.VpcEndpointId is empty")
			}
		case *regionalapiv1.PrivateLinkService_Connection_Gcp_:
			if conn.GetGcp() == nil {
				return errors.New("PrivateLinkService.Connections.Gcp is nil")
			}
			if conn.GetGcp().GetPrivateServiceConnectEndpoint() == "" {
				return errors.New("PrivateLinkService.Connections.Gcp.PrivateServiceConnectEndpoint is empty")
			}
		case *regionalapiv1.PrivateLinkService_Connection_Azure_:
			if conn.GetAzure() == nil {
				return errors.New("PrivateLinkService.Connections.Azure is nil")
			}
			if conn.GetAzure().GetPrivateEndpointResourceId() == "" {
				return errors.New("PrivateLinkService.connections.Azure.PrivateEndpointResourceId is empty")
			}
			if conn.GetAzure().GetPrivateIpAddress() == "" {
				return errors.New("PrivateLinkService.connections.Azure.PrivateIpAddress is empty")
			}
			ip := net.ParseIP(conn.GetAzure().GetPrivateIpAddress())
			if ip == nil {
				return errors.New("PrivateLinkService.connections.Azure.PrivateIpAddress is invalid")
			}
		default:
			return errors.New("PrivateLinkService.Connections.Info is invalid")
		}
	}
	return nil
}

type GetPrivateLinkServiceReqValidatable struct {
	*regionalapiv1.GetPrivateLinkServiceRequest
}

func (r *GetPrivateLinkServiceReqValidatable) Validate() error {
	if r == nil {
		return errors.New("request is nil")
	}
	if r.DataPlaneId == "" {
		return errors.New("dataPlaneId is empty")
	}
	if r.Id == "" {
		return errors.New("id is empty")
	}
	return nil
}

type DeletePrivateLinkServiceReqValidatable struct {
	*regionalapiv1.DeletePrivateLinkServiceRequest
}

func (r *DeletePrivateLinkServiceReqValidatable) Validate() error {
	if r == nil {
		return errors.New("request is nil")
	}
	if r.DataPlaneId == "" {
		return errors.New("dataPlaneId is empty")
	}
	if r.Id == "" {
		return errors.New("id is empty")
	}
	return nil
}

type UpdatePrivateLinkServiceReqValidatable struct {
	*regionalapiv1.UpdatePrivateLinkServiceRequest
}

func (r *UpdatePrivateLinkServiceReqValidatable) Validate() error {
	if r == nil {
		return errors.New("request is nil")
	}
	if r.DataPlaneId == "" {
		return errors.New("dataPlaneId is empty")
	}
	if r.Id == "" {
		return errors.New("id is nil")
	}
	for _, conn := range r.GetPrivateLinkConnections() {
		if conn.GetInfo() == nil {
			return errors.New("PrivateLinkService.Connections.Info is nil")
		}
		switch conn.GetInfo().(type) {
		case *regionalapiv1.PrivateLinkService_Connection_Aws_:
			if r.ValidateOnly {
				return errors.New("ValidateOnly is not supported for aws connection")
			}
			if conn.GetAws() == nil {
				return errors.New("PrivateLinkService.Connections.Aws is nil")
			}
			if conn.GetAws().GetVpcEndpointId() == "" {
				return errors.New("PrivateLinkService.Connections.Aws.VpcEndpointId is empty")
			}
		case *regionalapiv1.PrivateLinkService_Connection_Gcp_:
			if r.ValidateOnly {
				return errors.New("ValidateOnly is not supported for gcp connection")
			}
			if conn.GetGcp() == nil {
				return errors.New("PrivateLinkService.Connections.Gcp is nil")
			}
			if conn.GetGcp().GetPrivateServiceConnectEndpoint() == "" {
				return errors.New("PrivateLinkService.Connections.Gcp.PrivateServiceConnectEndpoint is empty")
			}
		case *regionalapiv1.PrivateLinkService_Connection_Azure_:
			if conn.GetAzure() == nil {
				return errors.New("PrivateLinkService.Connections.Azure is nil")
			}
			if conn.GetAzure().GetPrivateEndpointResourceId() == "" {
				return errors.New("PrivateLinkService.connections.Azure.PrivateEndpointResourceId is empty")
			}
			if conn.GetAzure().GetPrivateIpAddress() == "" {
				return errors.New("PrivateLinkService.connections.Azure.PrivateIpAddress is empty")
			}
			ip := net.ParseIP(conn.GetAzure().GetPrivateIpAddress())
			if ip == nil {
				return errors.New("PrivateLinkService.connections.Azure.PrivateIpAddress is invalid")
			}
		default:
			return errors.New("PrivateLinkService.Connections.Info is invalid")
		}
	}
	return nil
}
