package dataapi

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

	"github.com/gin-gonic/gin"
	"github.com/pingcap/log"
	"github.com/tidbcloud/observability/pkg/common/configs"
	"github.com/tidbcloud/observability/pkg/common/errors"
	"github.com/tidbcloud/observability/pkg/common/structs"
	"github.com/tidbcloud/observability/pkg/dataservice"
	"github.com/tidbcloud/observability/pkg/regionalapi/apiinterceptor"
	"go.uber.org/zap"
)

func QueryHistoricalMetrics(c *gin.Context) {
	uniqueKey := structs.ClusterUniqueKey{
		BizType:       c.Param("bizType"),
		TenantID:      c.Param("tenantID"),
		ProjectID:     c.Param("projectID"),
		ApplicationID: c.Param("applicationID"),
	}
	var noproject bool
	if len(c.Param("projectID")) == 0 {
		noproject = true
	}
	clusterInfo, err := dataservice.GetHandler().GetArchivedCluster(c, uniqueKey)
	if err != nil {
		apiinterceptor.Fail(c, err)
		return
	}

	vmClusters := configs.GetServiceInfo().VMClusterInfo
	if len(vmClusters) == 0 {
		apiinterceptor.Fail(c, errors.New(errors.UnrecognizedError, "cannot query historical metrics in region without vmcluster"))
		return
	}
	schemaAndHost := fmt.Sprintf(schemaAndHostTemplate, vmClusters[0].VMClusterName)

	url := c.Request.URL.String()
	if noproject {
		url = strings.ReplaceAll(url,
			fmt.Sprintf(historicalPathTemplateWithNoProject, uniqueKey.BizType, uniqueKey.TenantID, uniqueKey.ApplicationID),
			fmt.Sprintf(vmPathTemplate, clusterInfo.VMAccountID, clusterInfo.VMProjectID))
	} else {
		url = strings.ReplaceAll(url,
			fmt.Sprintf(historicalPathTemplate, uniqueKey.BizType, uniqueKey.TenantID, uniqueKey.ProjectID, uniqueKey.ApplicationID),
			fmt.Sprintf(vmPathTemplate, clusterInfo.VMAccountID, clusterInfo.VMProjectID))
	}

	log.Info("read historical metrics",
		zap.String("Full_URL", schemaAndHost+url),
		zap.String("Schema_And_Host", schemaAndHost),
		zap.String("URL", url))

	req, err := http.NewRequestWithContext(c, c.Request.Method, schemaAndHost+url, c.Request.Body)
	if err != nil {
		apiinterceptor.Fail(c, err)
		return
	}
	defer req.Body.Close()
	req.Header = c.Request.Header

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		apiinterceptor.Fail(c, err)
		return
	}
	defer resp.Body.Close()
	for k := range resp.Header {
		for j := range resp.Header[k] {
			c.Header(k, resp.Header[k][j])
		}
	}
	c.DataFromReader(resp.StatusCode, resp.ContentLength, resp.Header.Get("Content-Type"), resp.Body, make(map[string]string))
}

const schemaAndHostTemplate = "http://vmselect-%s.observability.svc.cluster.local:8481"
const vmPathTemplate = "/select/%s:%s/prometheus/api/v1/"
const historicalPathTemplate = "/api/v1/%s/orgs/%s/projects/%s/clusters/%s/prometheus/"
const historicalPathTemplateWithNoProject = "/api/v1/%s/orgs/%s/clusters/%s/prometheus/"

func proxyHandler(c *gin.Context) {
	uniqueKey := structs.ClusterUniqueKey{
		BizType:       c.Param("bizType"),
		TenantID:      c.Param("tenantID"),
		ProjectID:     c.Param("projectID"),
		ApplicationID: c.Param("applicationID"),
	}
	var noproject bool
	if len(c.Param("projectID")) == 0 {
		noproject = true
	}
	clusterInfo, err := dataservice.GetHandler().GetArchivedCluster(c, uniqueKey)
	if err != nil {
		apiinterceptor.Fail(c, err)
		return
	}

	vmClusters := configs.GetServiceInfo().VMClusterInfo
	if len(vmClusters) == 0 {
		apiinterceptor.Fail(c, errors.New(errors.UnrecognizedError, "cannot query historical metrics in region without vmcluster"))
		return
	}
	schemaAndHost := fmt.Sprintf(schemaAndHostTemplate, vmClusters[0].VMClusterName)

	urlStr := c.Request.URL.String()
	if noproject {
		urlStr = strings.ReplaceAll(urlStr,
			fmt.Sprintf(historicalPathTemplateWithNoProject, uniqueKey.BizType, uniqueKey.TenantID, uniqueKey.ApplicationID),
			fmt.Sprintf(vmPathTemplate, clusterInfo.VMAccountID, clusterInfo.VMProjectID))
	} else {
		urlStr = strings.ReplaceAll(urlStr,
			fmt.Sprintf(historicalPathTemplate, uniqueKey.BizType, uniqueKey.TenantID, uniqueKey.ProjectID, uniqueKey.ApplicationID),
			fmt.Sprintf(vmPathTemplate, clusterInfo.VMAccountID, clusterInfo.VMProjectID))
	}

	targetURL := schemaAndHost + urlStr

	log.Info("proxy any historical metrics",
		zap.String("Full_URL", targetURL),
		zap.String("Schema_And_Host", schemaAndHost),
		zap.String("URL", urlStr))

	req, err := http.NewRequestWithContext(c, c.Request.Method, targetURL, c.Request.Body)
	if err != nil {
		apiinterceptor.Fail(c, err)
		return
	}
	defer req.Body.Close()
	req.Header = c.Request.Header

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		apiinterceptor.Fail(c, err)
		return
	}
	defer resp.Body.Close()

	for k := range resp.Header {
		for j := range resp.Header[k] {
			c.Header(k, resp.Header[k][j])
		}
	}
	c.DataFromReader(resp.StatusCode, resp.ContentLength, resp.Header.Get("Content-Type"), resp.Body, make(map[string]string))
}
