package cluster_management

import (
	"context"
	"fmt"
	"sync"

	"github.com/tidbcloud/tiinf/errs"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	tigrpc "github.com/tidbcloud/tiinf/transport/tigrpc/client"
	"go.buf.build/protocolbuffers/go/linuxgit/tidbcloud/base"
	"go.uber.org/zap"
	"google.golang.org/grpc"

	"github.com/tidbcloud/core-svc/idl/pbgen/proto/core"

	"github.com/tidbcloud/auditlog/configs"
)

var (
	cmInitOnce sync.Once
	cmSvc      ClusterManageIface
)

type ClusterManageIface interface {
	GetClusterByID(ctx context.Context, clusterID uint64) (*core.Cluster, error)
}

func parseInfraResp(baseResp *base.BaseResp) error {
	if baseResp.ErrCode == errs.ErrCodeOK {
		return nil
	}

	return errs.NewInternalServerError("infra server error", nil)
}

func NewCMSvc(ctx context.Context, cfg *configs.Config) ClusterManageIface {
	cmInitOnce.Do(func() {
		var conn *grpc.ClientConn
		conn, err := tigrpc.NewClientConn(cfg.CMSvcAddr, tigrpc.WithDefault())
		tilog.Info(ctx, "Initializing account service client", zap.Any("err", err), zap.String("addr", cfg.AccountSvcAddr))
		if err != nil {
			panic(fmt.Sprintf("dial account-svc: %s", err))
		}

		cmClient := core.NewCoreServiceClient(conn)
		cmSvc = &cmSvcImpl{cmClient: cmClient}
	})

	return cmSvc
}

type cmSvcImpl struct {
	cmClient core.CoreServiceClient
}

func (c *cmSvcImpl) GetClusterByID(ctx context.Context, clusterID uint64) (*core.Cluster, error) {
	req := &core.ListClustersReq{
		Filter: &core.ClusterFilter{
			ClusterIds: []uint64{clusterID},
		},
	}
	resp, e := c.cmClient.ListClusters(ctx, req)
	if e != nil {
		return nil, errs.NewInternalGRPC("GetClusterByID", e)
	}

	if err := parseInfraResp(resp.BaseResp); err != nil {
		return nil, err
	}

	cluster, ok := resp.Clusters[clusterID]
	if !ok {
		return nil, errs.NewNotFound("cluster not found", nil)
	}

	return cluster, nil
}
