package api

import (
	"net/http"

	"github.com/gin-gonic/contrib/static"
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"github.com/tidbcloud/service-catalog/pkg/controller"
	"github.com/tidbcloud/service-catalog/pkg/model"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"github.com/tidbcloud/tiinf/transport/http/tigin"
	"go.uber.org/zap"
)

var provider *model.MetaProvider

func Init() error {
	var err error
	provider, err = model.NewMetaProvider(viper.GetString("metaPath"))
	return err
}

func RunServer() {
	engine := tigin.Default()

	engine.Use(static.Serve("/", static.LocalFile("./ui/dist/", true)))

	api := engine.Group("/api")
	api.GET("/services", ListServices)
	api.GET("/applications", ListApplications)
	api.GET("/services/:name", GetServiceMeta)
	api.GET("/applications/:name", GetApplication)
	api.GET("/topology", GetTopology)
	api.GET("/dependency", GetDependency)
	api.GET("/deployments", ListDeployments)
	engine.Run()
}

func ListDeployments(c *gin.Context) {
	deployments, _ := controller.ListDeployments(viper.GetString("serviceNamespace"))
	c.JSON(http.StatusOK, deployments)
}

func ListServices(c *gin.Context) {
	node, err := provider.BuildTree()
	if err != nil {
		tilog.Error(c.Request.Context(), "build tree from provider failed", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, node)
}

func ListApplications(c *gin.Context) {
	apps, err := provider.ListApplications(c.Request.Context())
	ctx := c.Request.Context()
	if err != nil {
		tilog.Error(ctx, "get meta from provider failed", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, apps)
}

func GetServiceMeta(c *gin.Context) {
	meta, err := provider.GetMeta(c.Request.Context(), c.Param("name"))
	ctx := c.Request.Context()
	if err != nil {
		tilog.Error(ctx, "get meta from provider failed", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if meta == nil {
		tilog.Error(ctx, "get empty meta")
		c.JSON(http.StatusNotFound, gin.H{"error": "NotFound"})
		return
	}
	c.JSON(http.StatusOK, meta)
}

func GetApplication(c *gin.Context) {
	application, err := provider.GetApplication(c.Request.Context(), c.Param("name"))
	ctx := c.Request.Context()
	if err != nil {
		tilog.Error(ctx, "get application from provider failed", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if application == nil {
		tilog.Error(ctx, "get empty application")
		c.JSON(http.StatusNotFound, gin.H{"error": "NotFound"})
		return
	}
	c.JSON(http.StatusOK, application)
}

func GetTopology(c *gin.Context) {
	ctx := c.Request.Context()
	topo, err := model.GetTopology(ctx, viper.GetString("jaegerAddr"))
	if err != nil {
		tilog.Error(ctx, "get topology failed", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, topo)
}

func GetDependency(c *gin.Context) {
	ctx := c.Request.Context()
	dep, err := model.GetDependency(ctx, viper.GetString("jaegerAddr"))
	if err != nil {
		tilog.Error(ctx, "get dependency failed", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, dep)
}
