package message

import (
	"errors"
	"fmt"
	"net"
	"strings"

	regionalapiv1 "github.com/tidbcloud/infra-provider/api/tidbcloud/regional-server/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.PrivateLinkService.Id == "" {
		return errors.New("PrivateLinkService.Id is empty")
	}
	if c.PrivateLinkService.ClusterId == "" {
		return errors.New("PrivateLinkService.ClusterId is empty")
	}
	if c.PrivateLinkService.TidbGroupId == "" {
		return errors.New("PrivateLinkService.TidbGroupId 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 ListPrivateLinkServiceReqValidatable struct {
	*regionalapiv1.ListPrivateLinkServicesRequest
}

func (r *ListPrivateLinkServiceReqValidatable) Validate() error {
	if r == nil {
		return errors.New("request is nil")
	}
	if r.ClusterId == "" {
		return errors.New("clusterId is empty")
	}
	return nil
}

type GetPrivateLinkServiceReqValidatable struct {
	*regionalapiv1.GetPrivateLinkServiceRequest
}

func (r *GetPrivateLinkServiceReqValidatable) Validate() error {
	if r == nil {
		return errors.New("request is nil")
	}
	if r.ClusterId == "" {
		return errors.New("clusterId is empty")
	}
	if r.PrivateLinkServiceId == "" {
		return errors.New("privateLinkServiceId 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.ClusterId == "" {
		return errors.New("clusterId is empty")
	}
	if r.PrivateLinkServiceId == "" {
		return errors.New("privateLinkServiceId is empty")
	}
	return nil
}

type RejectVpcEndpointConnectionsReqValidatable struct {
	*regionalapiv1.RejectVpcEndpointConnectionsRequest
}

func (r *RejectVpcEndpointConnectionsReqValidatable) Validate() error {
	if r == nil {
		return errors.New("request is nil")
	}
	if r.ClusterId == "" {
		return errors.New("clusterId is empty")
	}
	if r.PrivateLinkServiceId == "" {
		return errors.New("privateLinkServiceId is empty")
	}
	if len(r.VpcEndpointIds) == 0 {
		return errors.New("vpcEndpointIds is empty")
	}
	for i, id := range r.VpcEndpointIds {
		if strings.TrimSpace(id) == "" {
			return fmt.Errorf("vpcEndpointIds[%d] is empty", i)
		}
	}
	return nil
}

type UpdatePrivateLinkServiceReqValidatable struct {
	*regionalapiv1.UpdatePrivateLinkServiceRequest
}

func (r *UpdatePrivateLinkServiceReqValidatable) Validate() error {
	if r == nil {
		return errors.New("request is nil")
	}
	if r.ClusterId == "" {
		return errors.New("clusterId is empty")
	}
	if r.PrivateLinkServiceId == "" {
		return errors.New("privateLinkServiceId is empty")
	}
	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
}

type PausePrivateLinkServiceReqValidatable struct {
	*regionalapiv1.PausePrivateLinkServiceRequest
}

func (r *PausePrivateLinkServiceReqValidatable) Validate() error {
	if r == nil {
		return errors.New("request is nil")
	}
	if r.ClusterId == "" {
		return errors.New("clusterId is empty")
	}
	if r.PrivateLinkServiceId == "" {
		return errors.New("privateLinkServiceId is empty")
	}
	return nil
}

type PurgePrivateLinkMetadataReqValidatable struct {
	*regionalapiv1.PurgePrivateLinkMetadataRequest
}

func (r *PurgePrivateLinkMetadataReqValidatable) Validate() error {
	if r == nil {
		return errors.New("request is nil")
	}
	if r.ClusterId == "" {
		return errors.New("clusterId is empty")
	}
	if r.PrivateLinkServiceId == "" {
		return errors.New("privateLinkServiceId is empty")
	}
	return nil
}
