package topsql

import (
	"context"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/log"
	"go.uber.org/zap"

	apierr "github.com/pingcap-inc/clinic/pkg/api/error"
	"github.com/pingcap-inc/clinic/pkg/ngm/topsql/api"
	"github.com/pingcap-inc/clinic/pkg/ngm/topsql/vm"
	"github.com/pingcap-inc/clinic/pkg/ngm/utils"
	"github.com/pingcap-inc/clinic/pkg/o11y"
)

const (
	DefaultTimeout = time.Second * 180
)

func InitTopSQLApi(g *gin.RouterGroup, s *Service) {
	g.GET("/topsql/config", s.configHandler)
	g.GET("/topsql/instances", s.instancesHandler)
	g.GET("/topsql/summary", s.summaryHandler)
}

func NewTopSQLService(client *http.Client, env string, o11yCli *o11y.Client) (*Service, error) {
	v, err := vm.NewVmQuery(client, env)
	if err != nil {
		return nil, err
	}
	return &Service{Env: env, Query: v, o11yCli: o11yCli}, nil
}

type Service struct {
	Env     string
	Query   api.Query
	o11yCli *o11y.Client
}

type configResponse struct {
	Enable bool `json:"enable"`
}

type jsonResponse struct {
	Status string `json:"status"`
	Data   any    `json:"data"`
}

// @Summary		Get config of TopSQL
// @Tags			topsql
// @Description	get config of TopSQL
// @Produce		json
// @Success		200	{object}	configResponse
// @Router			/topsql/config [get]
func (s *Service) configHandler(c *gin.Context) {
	c.JSON(http.StatusOK, configResponse{true})
}

// @Summary		Get summary of TopSQL
// @Tags			topsql
// @Description	get summary of TopSQL
// @Produce		json
// @Param			X-Provider		header		string	true	"provider aws/gcp"
// @Param			X-Region		header		string	true	"region"
// @Param			X-Org-Id		header		string	true	"organization id from dbaas"
// @Param			X-Project-Id	header		string	true	"project id from dbaas"
// @Param			X-Cluster-Id	header		string	true	"cluster id from dbaas"
// @Param			start			query		string	true	"start time in unix seconds"
// @Param			end				query		string	true	"end time in unix seconds"
// @Param			window			query		string	true	"window in duration"
// @Param			top				query		int		true	"top n"
// @Param			instance		query		string	true	"instance name"
// @Param			instance_type	query		string	true	"instance type"
// @Success		200				{object}	jsonResponse{data=[]api.SummaryItem}
// @Router			/topsql/summary [get]
func (s *Service) summaryHandler(c *gin.Context) {
	var header ClusterHeader
	if err := c.BindHeader(&header); err != nil {
		log.Warn("failed to bind topsql summary header", zap.Error(err))
		_ = c.Error(apierr.ErrBadRequest.WrapWithNoMessage(err))
		return
	}
	if err := header.Validate(); err != nil {
		log.Warn("invalid topsql summary header", zap.Error(err))
		_ = c.Error(apierr.ErrBadRequest.WrapWithNoMessage(err))
		return
	}

	var query SummaryQuery
	if err := c.BindQuery(&query); err != nil {
		log.Warn("failed to bind topsql summary query", zap.Error(err))
		_ = c.Error(apierr.ErrBadRequest.WrapWithNoMessage(err))
		return
	}
	if err := query.Validate(); err != nil {
		log.Warn("invalid topsql summary query", zap.Error(err))
		_ = c.Error(apierr.ErrBadRequest.WrapWithNoMessage(err))
		return
	}

	ctx, cancel := context.WithTimeout(c.Request.Context(), DefaultTimeout)
	defer cancel()

	// params := &api.SummaryParams{
	// 	Provider:  *header.Provider,
	// 	Region:    *header.Region,
	// 	TenantID:  *header.TenantID,
	// 	ProjectID: *header.ProjectID,
	// 	ClusterID: *header.ClusterID,

	// 	StartSecs:    int(*query.StartSecs),
	// 	EndSecs:      int(*query.EndSecs),
	// 	WindowSecs:   int(*query.Window / time.Second),
	// 	Top:          *query.Top,
	// 	Instance:     *query.Instance,
	// 	InstanceType: *query.InstanceType,
	// }
	// var items []api.SummaryItem
	// var err error
	// if items, err = s.Query.Summary(ctx, params); err != nil {
	// 	log.Warn("failed to call topsql summary", zap.Error(err))
	// 	_ = c.Error(err)
	// 	return
	// }

	// c.JSON(http.StatusOK, jsonResponse{
	// 	Status: "ok",
	// 	Data:   items,
	// })

	err := utils.ProxyO11yByQueryCluster(ctx,
		c,
		s.o11yCli,
		header.DeployType,
		s.Env,
		*header.Provider,
		*header.Region,
		header.GetTenantID(),
		header.GetProjectID(),
		header.GetClusterID(),
		"/internal/diagnosis/api/v1/topsql/summary")
	if err != nil {
		log.Error("failed to proxy to o11y", zap.Error(err))
		_ = c.Error(apierr.ErrInternal.Wrap(err, "failed to proxy to o11y"))
		return
	}
}

// @Summary		Get available instances of TopSQL
// @Tags			topsql
// @Description	get available instances of TopSQL
// @Produce		json
// @Param			X-Provider		header		string	true	"provider aws/gcp"
// @Param			X-Region		header		string	true	"region"
// @Param			X-Org-Id		header		string	true	"organization id from dbaas"
// @Param			X-Project-Id	header		string	true	"project id from dbaas"
// @Param			X-Cluster-Id	header		string	true	"cluster id from dbaas"
// @Param			start			query		string	true	"start time in unix seconds"
// @Param			end				query		string	true	"end time in unix seconds"
// @Success		200				{object}	jsonResponse{data=[]api.InstanceItem}
// @Router			/topsql/instances [get]
func (s *Service) instancesHandler(c *gin.Context) {
	var header ClusterHeader
	if err := c.BindHeader(&header); err != nil {
		log.Warn("failed to bind topsql instances header", zap.Error(err))
		_ = c.Error(apierr.ErrBadRequest.New("%s", err.Error()))
		return
	}
	if err := header.Validate(); err != nil {
		log.Warn("invalid topsql instances header", zap.Error(err))
		_ = c.Error(apierr.ErrBadRequest.New("%s", err.Error()))
		return
	}

	var query InstanceQuery
	if err := c.BindQuery(&query); err != nil {
		log.Warn("failed to bind topsql instances query", zap.Error(err))
		_ = c.Error(apierr.ErrBadRequest.New("%s", err.Error()))
		return
	}
	if err := query.Validate(); err != nil {
		log.Warn("invalid topsql instances query", zap.Error(err))
		_ = c.Error(apierr.ErrBadRequest.New("%s", err.Error()))
		return
	}

	ctx, cancel := context.WithTimeout(c.Request.Context(), DefaultTimeout)
	defer cancel()

	// params := &api.InstancesParams{
	// 	Provider:  *header.Provider,
	// 	Region:    *header.Region,
	// 	TenantID:  *header.TenantID,
	// 	ProjectID: *header.ProjectID,
	// 	ClusterID: *header.ClusterID,

	// 	StartSecs: int(*query.StartSecs),
	// 	EndSecs:   int(*query.EndSecs),
	// }
	// var instances []api.InstanceItem
	// var err error
	// if instances, err = s.Query.Instances(ctx, params); err != nil {
	// 	log.Warn("failed to call topsql instance", zap.Error(err))
	// 	_ = c.Error(err)
	// 	return
	// }

	// c.JSON(http.StatusOK, jsonResponse{
	// 	Status: "ok",
	// 	Data:   instances,
	// })

	err := utils.ProxyO11yByQueryCluster(ctx,
		c,
		s.o11yCli,
		header.DeployType,
		s.Env,
		*header.Provider,
		*header.Region,
		header.GetTenantID(),
		header.GetProjectID(),
		header.GetClusterID(),
		"/internal/diagnosis/api/v1/topsql/instances")
	if err != nil {
		log.Error("failed to proxy to o11y", zap.Error(err))
		_ = c.Error(apierr.ErrInternal.Wrap(err, "failed to proxy to o11y"))
		return
	}
}
