package grpc_service

import (
	"context"

	"github.com/tidbcloud/config-center/internal/service"
	pb "github.com/tidbcloud/config-center/proto/config_center"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

func (s ConfigCenterService) GetClusterComponent(ctx context.Context, req *pb.GetClusterComponentRequest) (*pb.ClusterComponent, error) {
	return service.GetClusterComponent(s.DB, req)
}

func (s ConfigCenterService) ListClusterComponents(ctx context.Context, req *pb.ListClusterComponentsRequest) (*pb.ListClusterComponentsResponse, error) {
	return service.ListClusterComponents(s.DB, req)
}

func (s ConfigCenterService) SearchClusterComponents(ctx context.Context, req *pb.SearchClusterComponentsRequest) (*pb.SearchClusterComponentsResponse, error) {
	if s.ServiceMode == ModeGlobal && req.GetClusterType().UseRegionalMode() {
		if req.GetLogicalRegion() == "" {
			return nil, status.Error(codes.InvalidArgument, "logical_region is required for regional cluster type")
		}
		regionalClient := s.UnifiedService.GetRegionalClient(req.GetClusterType(), req.GetLogicalRegion())
		if regionalClient == nil {
			return nil, status.Errorf(codes.NotFound, "regional service not found for cluster_type %s and logical_region %s", req.GetClusterType().String(), req.GetLogicalRegion())
		}
		return regionalClient.SearchClusterComponents(ctx, req)
	}
	return service.SearchClusterComponents(s.DB, req)
}

func (s ConfigCenterService) UpdateClusterComponent(ctx context.Context, req *pb.UpdateClusterComponentRequest) (*pb.ClusterComponent, error) {
	tx, err := s.DB.Begin()
	if err != nil {
		return &pb.ClusterComponent{}, status.Error(codes.Internal, err.Error())
	}
	defer tx.Rollback()

	resp, err := service.UpdateClusterComponent(tx, req)
	if err != nil {
		return &pb.ClusterComponent{}, err
	}
	err = WriteAuditLog(tx, "UpdateClusterComponent", req.GetClusterType().String(), req.GetClusterId(), req, resp)
	if err != nil {
		return &pb.ClusterComponent{}, status.Error(codes.Internal, "failed to write audit log")
	}
	return resp, tx.Commit()
}

func (s ConfigCenterService) BatchUpdateClusterComponents(ctx context.Context, req *pb.BatchUpdateClusterComponentsRequest) (*pb.BatchUpdateClusterComponentsResponse, error) {
	if len(req.GetRequests()) == 0 {
		return &pb.BatchUpdateClusterComponentsResponse{}, status.Error(codes.InvalidArgument, "requests length should not be 0")
	}
	clusterType := req.GetRequests()[0].GetClusterType()
	clusterID := req.GetRequests()[0].GetClusterId()
	for _, r := range req.GetRequests() {
		if r.GetClusterType() != clusterType {
			return &pb.BatchUpdateClusterComponentsResponse{}, status.Error(codes.InvalidArgument, "all cluster type should be the same")
		}
		if r.GetClusterId() != clusterID {
			return &pb.BatchUpdateClusterComponentsResponse{}, status.Error(codes.InvalidArgument, "all clusterID should be the same")
		}
		if r.GetValidateOnly() && !req.GetValidateOnly() {
			return nil, status.Error(codes.InvalidArgument, "validate_only should be set at BatchUpdateClusterComponentsRequest")
		}
	}

	tx, err := s.DB.Begin()
	if err != nil {
		return &pb.BatchUpdateClusterComponentsResponse{}, status.Error(codes.Internal, err.Error())
	}
	resp, err := service.BatchUpdateClusterComponents(tx, req)
	if err != nil {
		tx.Rollback()
		return &pb.BatchUpdateClusterComponentsResponse{}, err
	}

	err = WriteAuditLog(tx, "BatchUpdateClusterComponents", clusterType.String(), clusterID, req, resp)
	if err != nil {
		tx.Rollback()
		return &pb.BatchUpdateClusterComponentsResponse{}, status.Error(codes.Internal, "failed to write audit log")
	}

	return resp, tx.Commit()
}
