package query

import (
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"
	"go.uber.org/dig"

	"github.com/tidbcloud/aisupport/packages/sdk-go/infra/apiserver"
	apiutils "github.com/tidbcloud/aisupport/packages/sdk-go/infra/apiserver/utils"
	"github.com/tidbcloud/aisupport/packages/sdk-go/infra/errs"
	"github.com/tidbcloud/aisupport/services/jsm-syncer/internal/app"
	querysvc "github.com/tidbcloud/aisupport/services/jsm-syncer/internal/services/query"
)

const (
	defaultClusterPageSize = 50
	maxClusterPageSize     = 100
)

type HandlerParam struct {
	dig.In

	Query querysvc.Service
}

type Handler struct {
	query querysvc.Service
}

func NewHandler(param HandlerParam) app.HandlerResult {
	return app.HandlerResult{
		Handler: &Handler{
			query: param.Query,
		},
	}
}

func (h *Handler) Name() string {
	return "QueryHandler"
}

func (h *Handler) Register(routers map[apiserver.RoutePath]gin.IRouter) error {
	router := routers[app.APIRoutePath]

	router.GET("/orgs", h.GetUserOrgs)
	router.GET("/orgs/:tidbcloud_org_id", h.GetOrgByID)
	router.GET("/orgs/:tidbcloud_org_id/users", h.GetUsersByOrgID)
	router.GET("/orgs/:tidbcloud_org_id/lakes", h.GetLakesByOrgID)
	router.GET("/lakes", h.GetUserLakes)
	router.GET("/clusters/:cluster_id", h.GetClusterByID)
	router.GET("/orgs/:tidbcloud_org_id/clusters", h.GetOrgClusters)

	forge := router.Group("/forge")
	forge.GET("/orgs", h.GetForgeUserOrgs)
	forge.GET("/lakes", h.GetForgeUserLakes)
	forge.GET("/orgs/:tidbcloud_org_id/lakes", h.GetForgeOrgLakes)
	forge.GET("/orgs/:tidbcloud_org_id/clusters", h.GetForgeOrgClusters)
	return nil
}

func parseClusterPageSize(c *gin.Context) (int, error) {
	raw := c.DefaultQuery("page_size", strconv.Itoa(defaultClusterPageSize))
	pageSize, err := strconv.Atoi(raw)
	if err != nil {
		return 0, errs.APIErrorNew(http.StatusBadRequest, err)
	}
	if pageSize <= 0 {
		return 0, errs.APIErrorf(http.StatusBadRequest, "page_size must be positive")
	}
	if pageSize > maxClusterPageSize {
		return maxClusterPageSize, nil
	}
	return pageSize, nil
}

func fail(c *gin.Context, err error) {
	apiutils.Fail(c, err)
}

func success(c *gin.Context, resp any) {
	apiutils.Success(c, resp)
}
