package services

import (
	"context"
	"fmt"

	dpmv1 "github.com/tidbcloud/cluster-service-ng/api/dataplane-manager/v1"
	"github.com/tidbcloud/cluster-service-ng/hack/mock-dpm/store"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"
)

// LoadBalancerService implements the LoadBalancerServiceServer interface.
type LoadBalancerService struct {
	dpmv1.UnimplementedLoadBalancerServiceServer
	store *store.MemoryStore
}

// NewLoadBalancerService creates a new LoadBalancerService.
func NewLoadBalancerService(s *store.MemoryStore) *LoadBalancerService {
	return &LoadBalancerService{store: s}
}

// CreateLoadBalancer creates a new load balancer.
func (s *LoadBalancerService) CreateLoadBalancer(ctx context.Context, req *dpmv1.CreateLoadBalancerRequest) (*dpmv1.LoadBalancer, error) {
	if req.DataPlaneId == "" || req.Id == "" {
		return nil, status.Error(codes.InvalidArgument, "data_plane_id and id are required")
	}
	if req.Loadbalancer == nil {
		return nil, status.Error(codes.InvalidArgument, "loadbalancer is required")
	}

	if existing, ok := s.store.GetLoadBalancer(req.DataPlaneId, req.Id); ok {
		return existing, nil
	}

	lb := &dpmv1.LoadBalancer{
		Id:          req.Id,
		Identity:    req.Loadbalancer.Identity,
		Namespace:   req.Loadbalancer.Namespace,
		Type:        req.Loadbalancer.Type,
		Port:        req.Loadbalancer.Port,
		Selectors:   req.Loadbalancer.Selectors,
		Tags:        req.Loadbalancer.Tags,
		IpWhiteList: req.Loadbalancer.IpWhiteList,
		Dns:         fmt.Sprintf("%s.%s.mock.tidbcloud.com", req.Id, req.DataPlaneId),
		Phase:       dpmv1.LoadBalancer_ACTIVE,
		PrivateIps:  []string{"10.0.1.100", "10.0.2.100"},
	}

	s.store.SetLoadBalancer(req.DataPlaneId, lb)
	return lb, nil
}

// UpdateLoadBalancer updates a load balancer.
func (s *LoadBalancerService) UpdateLoadBalancer(ctx context.Context, req *dpmv1.UpdateLoadBalancerRequest) (*dpmv1.LoadBalancer, error) {
	if req.DataPlaneId == "" || req.Id == "" {
		return nil, status.Error(codes.InvalidArgument, "data_plane_id and id are required")
	}
	if req.Loadbalancer == nil {
		return nil, status.Error(codes.InvalidArgument, "loadbalancer is required")
	}

	existing, ok := s.store.GetLoadBalancer(req.DataPlaneId, req.Id)
	if !ok {
		return nil, status.Error(codes.NotFound, "load balancer not found")
	}

	existing.Identity = req.Loadbalancer.Identity
	existing.Namespace = req.Loadbalancer.Namespace
	existing.Type = req.Loadbalancer.Type
	existing.Port = req.Loadbalancer.Port
	existing.Selectors = req.Loadbalancer.Selectors
	existing.Tags = req.Loadbalancer.Tags
	existing.IpWhiteList = req.Loadbalancer.IpWhiteList

	s.store.SetLoadBalancer(req.DataPlaneId, existing)
	return existing, nil
}

// GetLoadBalancer retrieves a load balancer by ID.
func (s *LoadBalancerService) GetLoadBalancer(ctx context.Context, req *dpmv1.GetLoadBalancerRequest) (*dpmv1.LoadBalancer, error) {
	if req.DataPlaneId == "" || req.Id == "" {
		return nil, status.Error(codes.InvalidArgument, "data_plane_id and id are required")
	}

	lb, ok := s.store.GetLoadBalancer(req.DataPlaneId, req.Id)
	if !ok {
		return nil, status.Error(codes.NotFound, "load balancer not found")
	}

	return lb, nil
}

// DeleteLoadBalancer deletes a load balancer.
func (s *LoadBalancerService) DeleteLoadBalancer(ctx context.Context, req *dpmv1.DeleteLoadBalancerRequest) (*emptypb.Empty, error) {
	if req.DataPlaneId == "" || req.Id == "" {
		return nil, status.Error(codes.InvalidArgument, "data_plane_id and id are required")
	}

	s.store.DeleteLoadBalancer(req.DataPlaneId, req.Id)
	return &emptypb.Empty{}, nil
}
