package nextgen

import (
	"encoding/json"
	"fmt"
	"net/url"
	"time"

	"github.com/smarty/assertions"
	"github.com/tidbcloud/observability/test/webconsolee2e/framework"
)

// MetricsQueryRangeNewPathCase test case for metrics query_range API using new path (nextgen)
type MetricsQueryRangeNewPathCase struct {
	Query string // PromQL query
	Step  int    // Query step in seconds
}

func NewMetricsQueryRangeNewPathCase(query string, step int) *MetricsQueryRangeNewPathCase {
	return &MetricsQueryRangeNewPathCase{
		Query: query,
		Step:  step,
	}
}

func (c *MetricsQueryRangeNewPathCase) Name() string {
	return "MetricsQueryRangeNewPath"
}

func (c *MetricsQueryRangeNewPathCase) Description() string {
	return "Verify metrics query_range API (gateway, nextgen) - depends on GetClusterRouteNewPath to get metricsOpenReadUri"
}

func (c *MetricsQueryRangeNewPathCase) Run(ctx *framework.TestContext) *framework.CaseResult {
	result := framework.NewCaseResult()

	// 1. Get metricsOpenReadUri from shared data (set by GetClusterRouteNewPathCase)
	metricsBaseURL := ctx.GetSharedString(KeyNewPathMetricsOpenReadUri)
	if metricsBaseURL == "" {
		result.AddError("newPathMetricsOpenReadUri not found in shared data - ensure GetClusterRouteNewPath runs first")
		return result
	}

	// 2. Build query parameters
	now := time.Now().Unix()
	start := now - 1800 // 30 minutes ago
	end := now
	step := c.Step
	if step == 0 {
		step = 120 // default 2 minutes
	}

	query := c.Query
	if query == "" {
		// Default query: TiDB memory usage
		query = "(sum(rate(resource_manager_resource_unit_read_request_unit_sum[1m])) or vector(0)) + (sum(rate(resource_manager_resource_unit_write_request_unit_sum[1m])) or vector(0))"
	}

	// 3. Build request URL
	// metricsBaseURL already ends with /api/v1/
	requestURL := fmt.Sprintf("%squery_range?start=%d&end=%d&step=%d&query=%s",
		metricsBaseURL,
		start,
		end,
		step,
		url.QueryEscape(query),
	)
	result.SetRequest("GET", requestURL, nil)

	// 4. Send request with newpath-specific headers
	client := ctx.GetNewPathClient()
	resp, err := client.Get(requestURL)
	if err != nil {
		result.AddError(fmt.Sprintf("Request failed: %v", err))
		return result
	}

	result.SetRequestWithHeaders(result.Request.Method, result.Request.URL, resp.RequestHeaders, result.Request.Body)
	result.SetResponseWithHeaders(resp.StatusCode, resp.GetResponseHeaders(), resp.String())

	// 5. Check common response headers (CORS)
	checker := framework.NewCommonResponseChecker(result, ctx.Origin)
	checker.CheckCORSHeaders(resp)
	checker.CheckStatusCode(resp, 200)

	// 6. Parse response body
	var respBody MetricsQueryResponse
	if err := json.Unmarshal(resp.Body, &respBody); err != nil {
		result.AddError(fmt.Sprintf("Failed to parse response JSON: %v", err))
		return result
	}

	// 7. Verify status is "success"
	if msg := assertions.ShouldEqual(respBody.Status, "success"); msg != "" {
		result.AddError(fmt.Sprintf("Status should be success: %s", msg))
	}

	// 8. Verify resultType is "matrix"
	if msg := assertions.ShouldEqual(respBody.Data.ResultType, "matrix"); msg != "" {
		result.AddError(fmt.Sprintf("ResultType should be matrix: %s", msg))
	}

	// 9. Verify result is not nil (but can be empty array if no data)
	if msg := assertions.ShouldNotBeNil(respBody.Data.Result); msg != "" {
		result.AddError(fmt.Sprintf("Result should not be nil: %s", msg))
	}

	return result
}
