package server

import (
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/serverless-metering/pkg/config"
	"github.com/tidbcloud/serverless-metering/pkg/monitor"
	"github.com/tidbcloud/serverless-metering/pkg/repository"
)

type MetaServer struct {
	addr   string
	engine *gin.Engine
	repo   *repository.CacheClusterBranchRepo
}

// @title			Serverless Meta Service
// @version		1.0
// @description	meta service is responsible for providing meta information of serverless resources.
// @host			meta-service.tidb-admin:8080
// @BasePath		/api/v1
func NewMetaServer(repo *repository.CacheClusterBranchRepo) *MetaServer {
	cfg := config.Global().Server
	engine := gin.Default()
	server := MetaServer{
		engine: engine,
		repo:   repo,
		addr:   cfg.MetaAddress,
	}
	group := engine.Group("/api/v1")
	group.GET("cluster-or-branch", server.GetClusterOrBranch)
	group.GET("diff-meta", server.DiffMetaData)
	return &server
}

func (s *MetaServer) Run() error {
	return s.engine.Run(s.addr)
}

// GetClusterOrBranch godoc
//
//	@Summary		Get cluster or branch by primary_id or keyspace_id
//	@Description	Get cluster or branch by primary_id or keyspace_id, either primary_id or keyspace_id should be provided.
//	@Produce		json
//	@Param			primary_id	query		string	false	"primary id of the cluster or branch"
//	@Param			keyspace_id	query		string	false	"keyspace id of the cluster or branch"
//	@Success		200			{object}	repository.ClusterBranch
//	@Router			/cluster-or-branch [get]
func (s *MetaServer) GetClusterOrBranch(c *gin.Context) {
	var statusCode int
	start := time.Now()
	path := "/cluster-or-branch"
	defer func() {
		monitor.MetaServerHttpRequestCounter.WithLabelValues(path, strconv.Itoa(statusCode)).Inc()
		monitor.MetaServerHttpDurationHistogram.WithLabelValues(path).Observe(time.Since(start).Seconds())
	}()

	ctx := c.Request.Context()
	primaryId := c.Query("primary_id")
	keyspaceId := c.Query("keyspace_id")
	if (primaryId == "" && keyspaceId == "") || (primaryId != "" && keyspaceId != "") {
		statusCode = http.StatusBadRequest
		c.JSON(statusCode, gin.H{"error": "either primary_id or keyspace_id should be provided"})
		return
	}

	var clusterBranch *repository.ClusterBranch
	var err error
	if primaryId != "" {
		clusterBranch, err = s.repo.GetClusterBranchByPrimaryID(ctx, primaryId)
	} else {
		clusterBranch, err = s.repo.GetClusterBranchByKeyspaceID(ctx, keyspaceId)
	}
	if err != nil {
		statusCode = http.StatusInternalServerError
		c.JSON(statusCode, gin.H{"error": err.Error()})
		return
	}

	statusCode = http.StatusOK
	c.JSON(statusCode, clusterBranch)
}

func (s *MetaServer) DiffMetaData(c *gin.Context) {
	var statusCode int
	start := time.Now()
	path := "/diff-meta"
	defer func() {
		monitor.MetaServerHttpRequestCounter.WithLabelValues(path, strconv.Itoa(statusCode)).Inc()
		monitor.MetaServerHttpDurationHistogram.WithLabelValues(path).Observe(time.Since(start).Seconds())
	}()

	result := s.repo.DiffMetaData()
	statusCode = http.StatusOK
	c.JSON(statusCode, result)
}
