package aiops

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"strings"

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

	"github.com/tidbcloud/devops/api"
	ctrl "github.com/tidbcloud/devops/pkg/controller"
	"github.com/tidbcloud/devops/pkg/infra/config"
	"github.com/tidbcloud/devops/pkg/infra/consts"
)

type ControllerParam struct {
	dig.In

	Conf   *config.RootConfig
	Logger logr.Logger
}

type AIOpsController struct {
	addr   string
	logger logr.Logger
}

func (c *AIOpsController) Name() string {
	return "AIOpsController"
}

func NewAIOpsController(p ControllerParam) ctrl.Controller {
	return &AIOpsController{
		addr:   p.Conf.Clients.AIOpsServer.Addr,
		logger: p.Logger.WithName("AIOpsController"),
	}
}

func (c *AIOpsController) RegisterAPI(suite *ctrl.Suite) error {
	r := suite.Router
	g := r.Group("/aiops")
	{

		g.Any("/proxy/*any", c.Proxy)
	}

	er := suite.ExternalRouter
	eg := er.Group("/aiops")
	{
		eg.Any("/proxy/*any", c.ProxyExternal)
	}
	return nil
}

func (c *AIOpsController) Proxy(ctx *gin.Context) {
	c.logger.Info("handle aiops proxy", "method", ctx.Request.Method, "path", ctx.Request.URL.Path, "user", ctx.GetString(consts.CtxOperator))

	proxyPath := ctx.Params.ByName("any")
	director := func(req *http.Request) {
		req.URL.Scheme = "http"
		req.URL.Host = c.addr
		req.URL.Path = proxyPath
		req.Header.Set("X-USER-EMAIL", ctx.GetString(consts.CtxUserEmail))
	}
	proxy := &httputil.ReverseProxy{Director: director}
	modifyFunc := func(resp *http.Response) error {
		resp.Header.Del("Access-Control-Allow-Origin")
		return nil
	}
	proxy.ModifyResponse = modifyFunc
	proxy.ServeHTTP(ctx.Writer, ctx.Request)
}

func (c *AIOpsController) ProxyExternal(ctx *gin.Context) {
	c.logger.Info("handle aiops external proxy", "method", ctx.Request.Method, "path", ctx.Request.URL.Path, "user", ctx.GetString(consts.CtxOperator))
	proxyPath := ctx.Params.ByName("any")
	if !strings.HasPrefix(proxyPath, "/api/v1/aiops-external") {
		ctrl.FailWithCode(ctx, fmt.Errorf("invalid proxy path: %s", proxyPath), api.ErrCodePermissionDenied)
		return
	}

	director := func(req *http.Request) {
		req.URL.Scheme = "http"
		req.URL.Host = c.addr
		req.URL.Path = proxyPath
	}
	proxy := &httputil.ReverseProxy{Director: director}
	modifyFunc := func(resp *http.Response) error {
		resp.Header.Del("Access-Control-Allow-Origin")
		return nil
	}
	proxy.ModifyResponse = modifyFunc
	proxy.ServeHTTP(ctx.Writer, ctx.Request)
}
