package cluster

import (
	"context"

	"github.com/pingcap/errors"
	"github.com/tidbcloud/core-portal/internal/central/grpc/grpcli"
	"github.com/tidbcloud/core-portal/internal/central/service/utils"
	"github.com/tidbcloud/core-svc/idl/pbgen/proto/central"
	"github.com/tidbcloud/core-svc/idl/pbgen/proto/core"
	entity "github.com/tidbcloud/core-svc/model"
	"github.com/tidbcloud/pkgv2/log"
	"go.uber.org/zap"
)

func (s *clusterService) CreatePrivateLinkService(ctx context.Context, req *central.CreatePrivateLinkServiceReq) (_ *central.CreatePrivateLinkServiceResp, rErr error) {
	orgID := req.OrgId
	projectID := req.ProjectId
	clusterID := req.ClusterId

	defer func() {
		utils.AuditLog(ctx, rErr, log.AuditEventType("AuditEventCreatePrivateLinkService"), zap.Uint64("project_id", projectID), zap.Uint64("cluster_id", clusterID))
	}()

	userContext := s.userCluster(ctx)
	err := userContext.CheckOrgIDAndProjectIDAndClusterID(ctx, orgID, projectID, clusterID)
	if err != nil {
		return nil, err
	}

	createReq := &core.CreatePrivateLinkServiceReq{
		OrgId:              orgID,
		ProjectId:          projectID,
		ClusterId:          clusterID,
		PrivatelinkService: &core.PrivateLinkService{},
	}

	resp, err := grpcli.CreatePrivateLinkService(ctx, createReq)
	if err != nil {
		return nil, err
	}

	return &central.CreatePrivateLinkServiceResp{
		PrivatelinkService: &central.PrivateLinkService{
			CloudProvider: resp.PrivatelinkService.CloudProvider,
			Status:        central.PrivateLinkService_Status(resp.PrivatelinkService.Status),
			DnsName:       resp.PrivatelinkService.DnsName,
			Port:          resp.PrivatelinkService.Port,
		},
		BaseResp: &central.BaseResp{},
	}, nil
}

func (s *clusterService) DeletePrivateLinkService(ctx context.Context, req *central.DeletePrivateLinkServiceReq) (_ *central.DefaultResp, rErr error) {
	orgID := req.OrgId
	projectID := req.ProjectId
	clusterID := req.ClusterId

	defer func() {
		utils.AuditLog(ctx, rErr, log.AuditEventType("AuditEventDeletePrivateLinkService"), zap.Uint64("project_id", projectID), zap.Uint64("cluster_id", clusterID))
	}()

	userContext := s.userCluster(ctx)
	err := userContext.CheckOrgIDAndProjectIDAndClusterID(ctx, orgID, projectID, clusterID)
	if err != nil {
		return nil, err
	}

	deleteReq := &core.DeletePrivateLinkServiceReq{
		OrgId:     orgID,
		ProjectId: projectID,
		ClusterId: clusterID,
	}
	err = grpcli.DeletePrivateLinkService(ctx, deleteReq)
	if err != nil {
		return nil, err
	}

	return &central.DefaultResp{
		BaseResp: &central.BaseResp{},
	}, nil
}

func (s *clusterService) GetPrivateLinkService(ctx context.Context, req *central.GetPrivateLinkServiceReq) (_ *central.GetPrivateLinkServiceResp, rErr error) {
	orgID := req.OrgId
	projectID := req.ProjectId
	clusterID := req.ClusterId

	defer func() {
		utils.AuditLog(ctx, rErr, log.AuditEventType("AuditEventGetPrivateLinkService"), zap.Uint64("project_id", projectID), zap.Uint64("cluster_id", clusterID))
	}()

	userContext := s.userCluster(ctx)
	err := userContext.CheckOrgIDAndProjectIDAndClusterID(ctx, orgID, projectID, clusterID)
	if err != nil {
		return nil, err
	}

	getReq := &core.GetPrivateLinkServiceReq{
		OrgId:     orgID,
		ProjectId: projectID,
		ClusterId: clusterID,
	}

	getResp, err := grpcli.GetPrivateLinkService(ctx, getReq)
	if err != nil {
		return nil, err
	}

	return &central.GetPrivateLinkServiceResp{
		PrivatelinkService: &central.PrivateLinkService{
			CloudProvider: getResp.PrivatelinkService.CloudProvider,
			Name:          getResp.PrivatelinkService.Name,
			DnsName:       getResp.PrivatelinkService.DnsName,
			Port:          getResp.PrivatelinkService.Port,
			Status:        central.PrivateLinkService_Status(getResp.PrivatelinkService.Status),
		},
		BaseResp: &central.BaseResp{},
	}, nil
}

func (s *clusterService) ListPrivateLinkEndpoints(ctx context.Context, req *central.ListPrivateLinkEndpointsReq) (resp *central.ListPrivateLinkEndpointsResp, rErr error) {
	orgID := req.OrgId
	projectID := req.ProjectId

	defer func() {
		utils.AuditLog(ctx, rErr, log.AuditEventType("AuditEventListPrivateLinkEndpoints"), zap.Uint64("project_id", projectID))
	}()

	userContext := s.userCluster(ctx)
	err := userContext.CheckOrgIDAndProjectID(entity.ID(orgID), entity.ID(projectID))
	if err != nil {
		return nil, err
	}

	listReq := &core.ListPrivateLinkEndpointsReq{
		OrgId:     orgID,
		ProjectId: projectID,
	}

	listResp, err := grpcli.ListPrivateLinkEndpoints(ctx, listReq)
	if err != nil {
		return nil, err
	}
	endpoints := make([]*central.PrivateLinkEndpoint, 0)
	for _, e := range listResp.Endpoints {
		endpoints = append(endpoints, &central.PrivateLinkEndpoint{
			CloudProvider: e.CloudProvider,
			ClusterId:     e.ClusterId,
			ClusterName:   e.ClusterName,
			RegionName:    e.RegionName,
			Id:            e.Id,
			Status:        central.PrivateLinkEndpoint_Status(e.Status),
			Message:       e.Message,
			ServiceName:   e.ServiceName,
			ServiceStatus: central.PrivateLinkService_Status(e.ServiceStatus),
		})
	}

	return &central.ListPrivateLinkEndpointsResp{
		Endpoints: endpoints,
		BaseResp:  &central.BaseResp{},
	}, nil
}

func (s *clusterService) CreatePrivateLinkEndpoint(ctx context.Context, req *central.CreatePrivateLinkEndpointReq) (_ *central.CreatePrivateLinkEndpointResp, rErr error) {
	orgID := req.OrgId
	projectID := req.ProjectId
	clusterID := req.ClusterId
	endpointID := req.PrivatelinkEndpoint.Id
	if len(endpointID) < 1 {
		return nil, errors.New("no endpoint ID")
	}

	defer func() {
		utils.AuditLog(ctx, rErr, log.AuditEventType("AuditEventCreatePrivateLinkEndpoint"), zap.Uint64("project_id", projectID), zap.Uint64("cluster_id", clusterID))
	}()

	userContext := s.userCluster(ctx)
	err := userContext.CheckOrgIDAndProjectIDAndClusterID(ctx, orgID, projectID, clusterID)
	if err != nil {
		return nil, err
	}

	createReq := &core.CreatePrivateLinkEndpointReq{
		OrgId:     orgID,
		ProjectId: projectID,
		ClusterId: clusterID,
		PrivatelinkEndpoint: &core.PrivateLinkEndpoint{
			Id: endpointID,
		},
	}
	resp, err := grpcli.CreatePrivateLinkEndpoint(ctx, createReq)
	if err != nil {
		return nil, err
	}

	return &central.CreatePrivateLinkEndpointResp{
		PrivatelinkEndpoint: &central.PrivateLinkEndpoint{
			CloudProvider: resp.PrivatelinkEndpoint.CloudProvider,
			ClusterId:     resp.PrivatelinkEndpoint.ClusterId,
			ClusterName:   resp.PrivatelinkEndpoint.ClusterName,
			RegionName:    resp.PrivatelinkEndpoint.RegionName,
			Id:            resp.PrivatelinkEndpoint.Id,
			Status:        central.PrivateLinkEndpoint_Status(resp.PrivatelinkEndpoint.Status),
			Message:       resp.PrivatelinkEndpoint.Message,
			ServiceName:   resp.PrivatelinkEndpoint.ServiceName,
			ServiceStatus: central.PrivateLinkService_Status(resp.PrivatelinkEndpoint.ServiceStatus),
		},
		BaseResp: &central.BaseResp{},
	}, nil
}

func (s *clusterService) DeletePrivateLinkEndpoint(ctx context.Context, req *central.DeletePrivateLinkEndpointReq) (_ *central.DefaultResp, rErr error) {
	orgID := req.OrgId
	projectID := req.ProjectId
	clusterID := req.ClusterId
	endpointID := req.EndpointId
	if len(endpointID) < 1 {
		return nil, errors.New("no endpoint ID")
	}

	defer func() {
		utils.AuditLog(ctx, rErr, log.AuditEventType("AuditEventDeletePrivateLinkEndpoint"), zap.Uint64("project_id", projectID), zap.Uint64("cluster_id", clusterID))
	}()

	userContext := s.userCluster(ctx)
	err := userContext.CheckOrgIDAndProjectIDAndClusterID(ctx, orgID, projectID, clusterID)
	if err != nil {
		return nil, err
	}

	deleteReq := &core.DeletePrivateLinkEndpointReq{
		OrgId:      orgID,
		ProjectId:  projectID,
		ClusterId:  clusterID,
		EndpointId: endpointID,
	}
	_, err = grpcli.DeletePrivateLinkEndpoint(ctx, deleteReq)
	if err != nil {
		return nil, err
	}

	return &central.DefaultResp{
		BaseResp: &central.BaseResp{},
	}, nil
}
