package vpc

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/log"
	regionalpb "github.com/tidbcloud/infra-provider/api/tidbcloud/regional-server/v1"
	bizerr "github.com/tidbcloud/infra-provider/regional-server/pkg/common/errors"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/common/message"
	rsconfig "github.com/tidbcloud/infra-provider/regional-server/pkg/config"
	resaccount "github.com/tidbcloud/infra-provider/regional-server/pkg/resourcemanager/account"
	resappbox "github.com/tidbcloud/infra-provider/regional-server/pkg/resourcemanager/appbox"
	resappcontroller "github.com/tidbcloud/infra-provider/regional-server/pkg/resourcemanager/appcontroller"
	resapproute "github.com/tidbcloud/infra-provider/regional-server/pkg/resourcemanager/approute"
	resinternet "github.com/tidbcloud/infra-provider/regional-server/pkg/resourcemanager/internet"
	resnamespace "github.com/tidbcloud/infra-provider/regional-server/pkg/resourcemanager/namespace"
	resvpc "github.com/tidbcloud/infra-provider/regional-server/pkg/resourcemanager/vpc"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/router/interceptor"
	svcaccount "github.com/tidbcloud/infra-provider/regional-server/pkg/service/account"
	sercluster "github.com/tidbcloud/infra-provider/regional-server/pkg/service/cluster"
	"go.uber.org/zap"
	emptypb "google.golang.org/protobuf/types/known/emptypb"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

type ClusterHandler struct {
	clustersvc *sercluster.ClusterService
}

func NewClusterHandler(cli client.Client, config rsconfig.RootConfig, tmplconfig rsconfig.TemplatesConfig) *ClusterHandler {
	return &ClusterHandler{
		clustersvc: sercluster.NewClusterService(
			resvpc.NewVPCReaderWriter(cli),
			resinternet.NewInternetReaderWriter(cli),
			resappbox.NewAPPBoxReaderWriter(cli),
			resappcontroller.NewAPPControllerReaderWriter(cli),
			resapproute.NewAPPRouteReaderWriter(cli),
			resnamespace.NewNamespaceReaderWriter(cli),
			svcaccount.NewService(resaccount.NewAccountReaderWriter(cli, config), resvpc.NewVPCReader(cli), config),
			svcaccount.NewSharedBucketService(resaccount.NewSharedBucketReaderWriter(cli, config)),
			resaccount.NewAccountReader(cli),
			config,
			tmplconfig,
		),
	}
}

func (r *ClusterHandler) CreateCluster(c *gin.Context) {
	req := &regionalpb.CreateClusterRequest{
		Cluster: &regionalpb.Cluster{},
	}
	if ok := interceptor.HandleJsonPbRequestFromBody(c, req.Cluster); !ok {
		log.Error("failed to handle json pb request from body")
		return
	}
	if err := (message.CreateClusterRequestValidatable{CreateClusterRequest: req}).Validate(); err != nil {
		log.Error("failed to validate create cluster request", zap.Any("req", req), zap.Error(err))
		interceptor.Fail(c, bizerr.New(bizerr.ParameterInvalid, err.Error()))
		return
	}
	cluster, err := r.clustersvc.Create(c, req)
	if err != nil {
		log.Error("failed to create cluster", zap.Any("req", req), zap.Error(err))
		interceptor.Fail(c, err)
	} else {
		interceptor.SucceedPb(c, http.StatusAccepted, &cluster)
	}
}

func (r *ClusterHandler) DeleteCluster(c *gin.Context) {
	clusterId := c.Param("clusterId")

	req := &regionalpb.DeleteClusterRequest{
		ClusterId: clusterId,
	}
	_, err := r.clustersvc.Delete(c, req)
	if err != nil {
		log.Error("failed to delete cluster", zap.Any("req", req), zap.Error(err))
		interceptor.Fail(c, err)
	} else {
		interceptor.SucceedPb(c, http.StatusOK, new(emptypb.Empty))
	}
}
