package cmd

import (
	"fmt"
	"strings"
	"testing"
	"time"

	"github.com/tidbcloud/clinic-cli/internal/config"
)

func TestRootVerbosePrintsResolutionSourcesAndRequests(t *testing.T) {
	t.Setenv("CLINIC_CLUSTER_ID", "cluster-from-env")

	cfg := testRootConfig("staging")
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		ActiveProfile: "blue",
		Profiles: map[string]config.ProfileRecord{
			"blue": {
				ClusterID:  "cluster-from-profile",
				RangeStart: "1712123000",
				RangeEnd:   "1712122000",
			},
		},
	}

	client := &recordingClinicClient{
		responses: []clinicResponse{
			{body: []byte(`{"status":"success","data":{"result":[]}}`)},
		},
	}

	runner := rootRunner{
		loadConfig: func() (*config.Config, error) {
			return cfg, nil
		},
		newClient: func(config.Environment) (Client, error) {
			return client, nil
		},
		handlers: map[string]commandHandler{
			"metrics": metricsCommandHandler,
		},
	}

	var stdout strings.Builder
	var stderr strings.Builder
	err := runner.runWithStderr([]string{
		"--verbose",
		"metrics",
		"range",
		"--query", "up",
		"--end", "1712123600",
		"--output", "json",
	}, &stdout, &stderr)
	if err != nil {
		t.Fatalf("runWithStderr() error = %v", err)
	}

	assertContainsAll(t, stderr.String(), []string{
		`selected env: "staging" (source: active_env)`,
		`selected profile: "blue" (source: active_profile)`,
		`env vars: CLINIC_CLUSTER_ID="cluster-from-env", CLINIC_RANGE_START=<unset>, CLINIC_RANGE_END=<unset>`,
		`profile defaults: cluster_id="cluster-from-profile", range_start="1712123000", range_end="1712122000"`,
		`resolved --cluster-id from env CLINIC_CLUSTER_ID: "cluster-from-env"`,
		fmt.Sprintf(`resolved --start from selected profile range_start: "1712123000" (%s)`, mustFormatResolvedTimeForDiagnostics(t, "1712123000")),
		fmt.Sprintf(`resolved --end from flag --end: "1712123600" (%s)`, mustFormatResolvedTimeForDiagnostics(t, "1712123600")),
		`request: GET /data-proxy/metrics/cluster-from-env/api/v1/query_range?`,
		`request query: end=1712123600&query=up&start=1712123000&step=15s`,
	})

	if got, want := client.request.Path, "/data-proxy/metrics/cluster-from-env/api/v1/query_range"; got != want {
		t.Fatalf("path = %q, want %q", got, want)
	}
	assertQueryValue(t, client.request.Query, "start", "1712123000")
	assertQueryValue(t, client.request.Query, "end", "1712123600")
}

func TestRootVerbosePrintsReadableLokiQueryArgument(t *testing.T) {
	cfg := testRootConfig("staging")
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		ActiveProfile: "blue",
		Profiles: map[string]config.ProfileRecord{
			"blue": {
				ClusterID:           "cluster-42",
				OrgID:               "org-1",
				ClusterDeployTypeV2: "dedicated",
			},
		},
	}

	client := &recordingClinicClient{
		responses: []clinicResponse{
			{body: []byte(`{"status":"success","data":{"resultType":"streams","result":[]}}`)},
		},
	}

	runner := rootRunner{
		loadConfig: func() (*config.Config, error) {
			return cfg, nil
		},
		newClient: func(config.Environment) (Client, error) {
			return client, nil
		},
		handlers: map[string]commandHandler{
			"loki": lokiCommandHandler,
		},
	}

	var stdout strings.Builder
	var stderr strings.Builder
	err := runner.runWithStderr([]string{
		"--verbose",
		"loki",
		"query",
		"--cluster-id", "cluster-42",
		"--start", "1712123000",
		"--end", "1712123600",
		"--output", "json",
		`{component="worker-tidb"}`,
	}, &stdout, &stderr)
	if err != nil {
		t.Fatalf("runWithStderr() error = %v", err)
	}

	assertContainsAll(t, stderr.String(), []string{
		`request: GET /data-proxy/loki/cluster-42/api/v1/query_range?`,
		`request query[query]: {component="worker-tidb", cluster_env="staging", namespace="tidbcluster-42"}`,
	})

	if got, want := len(client.requests), 1; got != want {
		t.Fatalf("request count = %d, want %d", got, want)
	}
	assertQueryValue(t, client.request.Query, "query", `{component="worker-tidb", cluster_env="staging", namespace="tidbcluster-42"}`)
}

func mustFormatResolvedTimeForDiagnostics(t *testing.T, raw string) string {
	t.Helper()

	unixNano, err := parseFlexibleTimeToUnixNano(raw, time.Local)
	if err != nil {
		t.Fatalf("parseFlexibleTimeToUnixNano(%q) error = %v", raw, err)
	}

	return time.Unix(0, unixNano).In(time.Local).Format("2006/01/02 15:04:05.000 -07:00")
}
