package cmd

import (
	"bytes"
	"encoding/json"
	"strings"
	"testing"

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

type profileJSON struct {
	Name                string `json:"name"`
	Env                 string `json:"env"`
	ClusterID           string `json:"cluster_id"`
	ClusterName         string `json:"cluster_name"`
	OrgID               string `json:"org_id"`
	ClinicURL           string `json:"clinic_url"`
	ParentID            string `json:"parent_id"`
	ClusterDeployTypeV2 string `json:"cluster_deploy_type_v2"`
	RangeStart          string `json:"range_start"`
	RangeEnd            string `json:"range_end"`
	Active              bool   `json:"active"`
}

func TestProfileCurrentIncludesClinicURL(t *testing.T) {
	setTestConfigHome(t)

	cfg := mustLoadConfig(t)
	cfg.ActiveEnv = "staging"
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		ActiveProfile: "blue",
		Profiles: map[string]config.ProfileRecord{
			"blue": {
				ClusterID: "cluster-42",
				OrgID:     "org-42",
			},
		},
	}
	if err := cfg.Save(); err != nil {
		t.Fatalf("cfg.Save() error = %v", err)
	}

	var stdout bytes.Buffer
	if err := RunWithIO([]string{"profile", "current"}, &stdout); err != nil {
		t.Fatalf("RunWithIO(profile current) error = %v", err)
	}

	var got struct {
		Profile *profileJSON `json:"profile"`
	}
	if err := json.Unmarshal(stdout.Bytes(), &got); err != nil {
		t.Fatalf("json.Unmarshal(profile current) error = %v\noutput=%s", err, stdout.String())
	}
	if got.Profile == nil {
		t.Fatal("profile = nil, want active profile")
	}
	if got, want := got.Profile.ClinicURL, "https://staging-clinic.pingcap.com/portal/#/orgs/org-42/clusters/cluster-42"; got != want {
		t.Fatalf("profile.clinic_url = %q, want %q", got, want)
	}
}

func TestProfileCurrentIncludesClinicURLUsingConfiguredEndpoint(t *testing.T) {
	setTestConfigHome(t)

	cfg := mustLoadConfig(t)
	cfg.ActiveEnv = "staging"
	cfg.Environments["staging"] = config.Environment{
		URL: "https://custom-clinic.example.com/",
	}
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		ActiveProfile: "blue",
		Profiles: map[string]config.ProfileRecord{
			"blue": {
				ClusterID: "cluster-42",
				OrgID:     "org-42",
			},
		},
	}
	if err := cfg.Save(); err != nil {
		t.Fatalf("cfg.Save() error = %v", err)
	}

	var stdout bytes.Buffer
	if err := RunWithIO([]string{"profile", "current"}, &stdout); err != nil {
		t.Fatalf("RunWithIO(profile current) error = %v", err)
	}

	var got struct {
		Profile *profileJSON `json:"profile"`
	}
	if err := json.Unmarshal(stdout.Bytes(), &got); err != nil {
		t.Fatalf("json.Unmarshal(profile current) error = %v\noutput=%s", err, stdout.String())
	}
	if got.Profile == nil {
		t.Fatal("profile = nil, want active profile")
	}
	if got, want := got.Profile.ClinicURL, "https://custom-clinic.example.com/portal/#/orgs/org-42/clusters/cluster-42"; got != want {
		t.Fatalf("profile.clinic_url = %q, want %q", got, want)
	}
}

func TestProfileListScopesToSelectedEnv(t *testing.T) {
	setTestConfigHome(t)

	cfg := mustLoadConfig(t)
	cfg.ActiveEnv = "prod"
	cfg.EnvProfiles["prod"] = config.EnvProfileContainer{
		ActiveProfile: "shared",
		Profiles: map[string]config.ProfileRecord{
			"prod-only": {
				ClusterID: "prod-cluster",
			},
			"shared": {
				ClusterID: "prod-shared",
			},
		},
	}
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		ActiveProfile: "shared",
		Profiles: map[string]config.ProfileRecord{
			"shared": {
				ClusterID:  "staging-shared",
				RangeStart: "10",
				RangeEnd:   "20",
			},
			"staging-only": {
				ClusterID: "staging-cluster",
			},
		},
	}
	if err := cfg.Save(); err != nil {
		t.Fatalf("cfg.Save() error = %v", err)
	}

	var stdout bytes.Buffer
	if err := RunWithIO([]string{"--env", "staging", "profile", "list"}, &stdout); err != nil {
		t.Fatalf("RunWithIO(profile list) error = %v", err)
	}

	var got struct {
		Env           string        `json:"env"`
		ActiveProfile string        `json:"active_profile"`
		Profiles      []profileJSON `json:"profiles"`
	}
	if err := json.Unmarshal(stdout.Bytes(), &got); err != nil {
		t.Fatalf("json.Unmarshal(profile list) error = %v\noutput=%s", err, stdout.String())
	}

	if got.Env != "staging" {
		t.Fatalf("env = %q, want %q", got.Env, "staging")
	}
	if got.ActiveProfile != "shared" {
		t.Fatalf("active_profile = %q, want %q", got.ActiveProfile, "shared")
	}
	if len(got.Profiles) != 2 {
		t.Fatalf("len(profiles) = %d, want 2", len(got.Profiles))
	}

	if got.Profiles[0].Name != "shared" || got.Profiles[0].ClusterID != "staging-shared" || !got.Profiles[0].Active {
		t.Fatalf("profiles[0] = %+v, want active staging shared profile", got.Profiles[0])
	}
	if got.Profiles[1].Name != "staging-only" || got.Profiles[1].ClusterID != "staging-cluster" || got.Profiles[1].Active {
		t.Fatalf("profiles[1] = %+v, want inactive staging-only profile", got.Profiles[1])
	}
}

func TestProfileCurrentReturnsNullWithoutActiveProfile(t *testing.T) {
	setTestConfigHome(t)

	cfg := mustLoadConfig(t)
	cfg.ActiveEnv = "staging"
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		Profiles: map[string]config.ProfileRecord{
			"blue": {
				ClusterID: "cluster-blue",
			},
		},
	}
	if err := cfg.Save(); err != nil {
		t.Fatalf("cfg.Save() error = %v", err)
	}

	var stdout bytes.Buffer
	if err := RunWithIO([]string{"profile", "current"}, &stdout); err != nil {
		t.Fatalf("RunWithIO(profile current) error = %v", err)
	}

	var got struct {
		Env           string       `json:"env"`
		ActiveProfile string       `json:"active_profile"`
		Profile       *profileJSON `json:"profile"`
	}
	if err := json.Unmarshal(stdout.Bytes(), &got); err != nil {
		t.Fatalf("json.Unmarshal(profile current) error = %v\noutput=%s", err, stdout.String())
	}

	if got.Env != "staging" {
		t.Fatalf("env = %q, want %q", got.Env, "staging")
	}
	if got.ActiveProfile != "" {
		t.Fatalf("active_profile = %q, want empty", got.ActiveProfile)
	}
	if got.Profile != nil {
		t.Fatalf("profile = %+v, want nil", got.Profile)
	}
}

func TestProfileUseUpdatesSelectedEnvOnly(t *testing.T) {
	setTestConfigHome(t)

	cfg := mustLoadConfig(t)
	cfg.EnvProfiles["prod"] = config.EnvProfileContainer{
		ActiveProfile: "shared",
		Profiles: map[string]config.ProfileRecord{
			"shared": {
				ClusterID: "prod-shared",
			},
		},
	}
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		Profiles: map[string]config.ProfileRecord{
			"shared": {
				ClusterID: "staging-shared",
			},
			"blue": {
				ClusterID: "staging-blue",
			},
		},
	}
	if err := cfg.Save(); err != nil {
		t.Fatalf("cfg.Save() error = %v", err)
	}

	var stdout bytes.Buffer
	if err := RunWithIO([]string{"--env", "staging", "profile", "use", "shared"}, &stdout); err != nil {
		t.Fatalf("RunWithIO(profile use) error = %v", err)
	}

	loaded := mustLoadConfig(t)
	if got := loaded.EnvProfiles["staging"].ActiveProfile; got != "shared" {
		t.Fatalf("EnvProfiles[staging].ActiveProfile = %q, want %q", got, "shared")
	}
	if got := loaded.EnvProfiles["prod"].ActiveProfile; got != "shared" {
		t.Fatalf("EnvProfiles[prod].ActiveProfile = %q, want %q", got, "shared")
	}

	var got struct {
		Env           string       `json:"env"`
		ActiveProfile string       `json:"active_profile"`
		Profile       *profileJSON `json:"profile"`
	}
	if err := json.Unmarshal(stdout.Bytes(), &got); err != nil {
		t.Fatalf("json.Unmarshal(profile use) error = %v\noutput=%s", err, stdout.String())
	}

	if got.Env != "staging" || got.ActiveProfile != "shared" {
		t.Fatalf("output env/active = %+v, want staging/shared", got)
	}
	if got.Profile == nil {
		t.Fatal("profile = nil, want selected staging profile")
	}
	if got.Profile.ClusterID != "staging-shared" || !got.Profile.Active {
		t.Fatalf("profile = %+v, want active staging shared profile", got.Profile)
	}
}

func TestProfileSetRequiresClusterID(t *testing.T) {
	setTestConfigHome(t)

	err := RunWithIO([]string{"--env", "staging", "profile", "set", "blue"}, &bytes.Buffer{})
	if err == nil {
		t.Fatal("RunWithIO(profile set) error = nil, want validation error")
	}
	if got := err.Error(); got != "missing required --cluster-id" {
		t.Fatalf("RunWithIO(profile set) error = %q, want %q", got, "missing required --cluster-id")
	}
}

func TestProfileSetUpdatesRangeWithoutClusterIDWhenExistingProfileHasClusterID(t *testing.T) {
	setTestConfigHome(t)

	cfg := mustLoadConfig(t)
	cfg.ActiveEnv = "staging"
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		ActiveProfile: "green",
		Profiles: map[string]config.ProfileRecord{
			"green": {
				ClusterID: "staging-green",
			},
			"blue": {
				ClusterID:           "cluster-42",
				ClusterName:         "cluster-blue",
				OrgID:               "org-42",
				ParentID:            "parent-42",
				ClusterDeployTypeV2: "dedicated",
				RangeStart:          "old-start",
				RangeEnd:            "old-end",
			},
		},
	}
	if err := cfg.Save(); err != nil {
		t.Fatalf("cfg.Save() error = %v", err)
	}

	client := &recordingClinicClient{}
	ctx := &RuntimeContext{
		SelectedEnv: "staging",
		Config:      cfg,
		Client:      client,
	}

	var stdout bytes.Buffer
	if err := profileCommandHandler(ctx, []string{"set", "blue", "--start", "10"}, &stdout); err != nil {
		t.Fatalf("profileCommandHandler(profile set range-only) error = %v", err)
	}

	if got := len(client.requests); got != 0 {
		t.Fatalf("request count = %d, want 0 for range-only update", got)
	}

	loaded := mustLoadConfig(t)
	stagingProfiles := loaded.EnvProfiles["staging"]
	blue, ok := stagingProfiles.Profiles["blue"]
	if !ok {
		t.Fatal("EnvProfiles[staging].Profiles[blue] missing after profile set")
	}
	if blue.ClusterID != "cluster-42" ||
		blue.ClusterName != "cluster-blue" ||
		blue.OrgID != "org-42" ||
		blue.ParentID != "parent-42" ||
		blue.ClusterDeployTypeV2 != "dedicated" {
		t.Fatalf("blue fixed metadata mutated unexpectedly: %+v", blue)
	}
	if blue.RangeStart != "10" {
		t.Fatalf("blue.RangeStart = %q, want %q", blue.RangeStart, "10")
	}
	if blue.RangeEnd != "old-end" {
		t.Fatalf("blue.RangeEnd = %q, want %q", blue.RangeEnd, "old-end")
	}
}

func TestProfileSetWithoutClusterIDFailsWhenExistingProfileHasNoClusterID(t *testing.T) {
	setTestConfigHome(t)

	cfg := mustLoadConfig(t)
	cfg.ActiveEnv = "staging"
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		Profiles: map[string]config.ProfileRecord{
			"blue": {
				RangeEnd: "old-end",
			},
		},
	}
	if err := cfg.Save(); err != nil {
		t.Fatalf("cfg.Save() error = %v", err)
	}

	err := RunWithIO([]string{"--env", "staging", "profile", "set", "blue", "--start", "10"}, &bytes.Buffer{})
	if err == nil {
		t.Fatal("RunWithIO(profile set range-only without stored cluster_id) error = nil, want validation error")
	}
	if got := err.Error(); got != "missing required --cluster-id" {
		t.Fatalf("RunWithIO(profile set range-only without stored cluster_id) error = %q, want %q", got, "missing required --cluster-id")
	}
}

func TestProfileSetCurrentTargetsActiveProfile(t *testing.T) {
	setTestConfigHome(t)

	cfg := mustLoadConfig(t)
	cfg.ActiveEnv = "staging"
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		ActiveProfile: "green",
		Profiles: map[string]config.ProfileRecord{
			"green": {
				ClusterID:  "cluster-green",
				RangeStart: "old-start",
				RangeEnd:   "old-end",
			},
			"blue": {
				ClusterID: "cluster-blue",
			},
		},
	}
	if err := cfg.Save(); err != nil {
		t.Fatalf("cfg.Save() error = %v", err)
	}

	var stdout bytes.Buffer
	if err := RunWithIO([]string{"--env", "staging", "profile", "set", "current", "--start", "10"}, &stdout); err != nil {
		t.Fatalf("RunWithIO(profile set current) error = %v", err)
	}

	loaded := mustLoadConfig(t)
	stagingProfiles := loaded.EnvProfiles["staging"]
	if stagingProfiles.ActiveProfile != "green" {
		t.Fatalf("EnvProfiles[staging].ActiveProfile = %q, want %q", stagingProfiles.ActiveProfile, "green")
	}

	green, ok := stagingProfiles.Profiles["green"]
	if !ok {
		t.Fatal("EnvProfiles[staging].Profiles[green] missing after profile set current")
	}
	if green.RangeStart != "10" {
		t.Fatalf("green.RangeStart = %q, want %q", green.RangeStart, "10")
	}
	if green.RangeEnd != "old-end" {
		t.Fatalf("green.RangeEnd = %q, want %q", green.RangeEnd, "old-end")
	}
	if _, exists := stagingProfiles.Profiles["current"]; exists {
		t.Fatal("EnvProfiles[staging].Profiles[current] exists, want reserved alias behavior")
	}

	var got struct {
		Env           string       `json:"env"`
		ActiveProfile string       `json:"active_profile"`
		Profile       *profileJSON `json:"profile"`
	}
	if err := json.Unmarshal(stdout.Bytes(), &got); err != nil {
		t.Fatalf("json.Unmarshal(profile set current) error = %v\noutput=%s", err, stdout.String())
	}
	if got.Env != "staging" || got.ActiveProfile != "green" {
		t.Fatalf("output env/active = %+v, want staging/green", got)
	}
	if got.Profile == nil {
		t.Fatal("profile = nil, want active profile output")
	}
	if got.Profile.Name != "green" || !got.Profile.Active {
		t.Fatalf("profile = %+v, want active green profile output", got.Profile)
	}
}

func TestProfileSetCurrentFailsWithoutActiveProfile(t *testing.T) {
	setTestConfigHome(t)

	cfg := mustLoadConfig(t)
	cfg.ActiveEnv = "staging"
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		Profiles: map[string]config.ProfileRecord{
			"blue": {
				ClusterID: "cluster-blue",
			},
		},
	}
	if err := cfg.Save(); err != nil {
		t.Fatalf("cfg.Save() error = %v", err)
	}

	err := RunWithIO([]string{"--env", "staging", "profile", "set", "current", "--start", "10"}, &bytes.Buffer{})
	if err == nil {
		t.Fatal("RunWithIO(profile set current without active profile) error = nil, want validation error")
	}
	if got, want := err.Error(), "profile set current requires an active profile in env staging"; got != want {
		t.Fatalf("RunWithIO(profile set current without active profile) error = %q, want %q", got, want)
	}
}

func TestProfileSetFetchesExactClusterMetadataWithoutSwitchingActiveProfile(t *testing.T) {
	setTestConfigHome(t)

	cfg := mustLoadConfig(t)
	cfg.ActiveEnv = "staging"
	cfg.EnvProfiles["prod"] = config.EnvProfileContainer{
		ActiveProfile: "blue",
		Profiles: map[string]config.ProfileRecord{
			"blue": {
				ClusterID: "prod-blue",
			},
		},
	}
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		ActiveProfile: "green",
		Profiles: map[string]config.ProfileRecord{
			"green": {
				ClusterID: "staging-green",
			},
			"blue": {
				ClusterID:   "old-cluster",
				RangeEnd:    "existing-end",
				ClusterName: "outdated-name",
				OrgID:       "outdated-org",
			},
		},
	}
	if err := cfg.Save(); err != nil {
		t.Fatalf("cfg.Save() error = %v", err)
	}

	client := &recordingClinicClient{
		responses: []clinicResponse{
			{body: []byte(`{"items":[{"clusterID":"branch-cluster-42","orgID":"org-branch","parentID":"parent-branch","clusterDeployTypeV2":"premium","name":"wrong-cluster"},{"clusterID":"cluster-42","orgID":"org-42","parentID":"parent-42","clusterDeployTypeV2":"dedicated","name":"cluster-blue"}]}`)},
		},
	}
	ctx := &RuntimeContext{
		SelectedEnv: "staging",
		Config:      cfg,
		Client:      client,
	}

	var stdout bytes.Buffer
	if err := profileCommandHandler(ctx, []string{"set", "blue", "--cluster-id", "cluster-42", "--start", "10"}, &stdout); err != nil {
		t.Fatalf("profileCommandHandler(profile set) error = %v", err)
	}

	if got, want := len(client.requests), 1; got != want {
		t.Fatalf("request count = %d, want %d", got, want)
	}
	assertQueryValue(t, client.requests[0].Query, "cluster_id", "cluster-42")
	assertQueryValue(t, client.requests[0].Query, "show_deleted", "true")

	loaded := mustLoadConfig(t)
	stagingProfiles := loaded.EnvProfiles["staging"]
	blue, ok := stagingProfiles.Profiles["blue"]
	if !ok {
		t.Fatal("EnvProfiles[staging].Profiles[blue] missing after profile set")
	}
	if blue.ClusterID != "cluster-42" {
		t.Fatalf("blue.ClusterID = %q, want %q", blue.ClusterID, "cluster-42")
	}
	if blue.ClusterName != "cluster-blue" {
		t.Fatalf("blue.ClusterName = %q, want %q", blue.ClusterName, "cluster-blue")
	}
	if blue.OrgID != "org-42" || blue.ParentID != "parent-42" {
		t.Fatalf("blue org/parent = %+v, want org-42/parent-42", blue)
	}
	if blue.ClusterDeployTypeV2 != "dedicated" {
		t.Fatalf("blue.ClusterDeployTypeV2 = %q, want %q", blue.ClusterDeployTypeV2, "dedicated")
	}
	if blue.RangeStart != "10" {
		t.Fatalf("blue.RangeStart = %q, want %q", blue.RangeStart, "10")
	}
	if blue.RangeEnd != "existing-end" {
		t.Fatalf("blue.RangeEnd = %q, want %q", blue.RangeEnd, "existing-end")
	}
	if stagingProfiles.ActiveProfile != "green" {
		t.Fatalf("EnvProfiles[staging].ActiveProfile = %q, want %q", stagingProfiles.ActiveProfile, "green")
	}
	if got := loaded.EnvProfiles["prod"].Profiles["blue"].ClusterID; got != "prod-blue" {
		t.Fatalf("EnvProfiles[prod].Profiles[blue].ClusterID = %q, want %q", got, "prod-blue")
	}

	var got struct {
		Env           string       `json:"env"`
		ActiveProfile string       `json:"active_profile"`
		Profile       *profileJSON `json:"profile"`
	}
	if err := json.Unmarshal(stdout.Bytes(), &got); err != nil {
		t.Fatalf("json.Unmarshal(profile set) error = %v\noutput=%s", err, stdout.String())
	}

	if got.Env != "staging" || got.ActiveProfile != "green" {
		t.Fatalf("output env/active = %+v, want staging/green", got)
	}
	if got.Profile == nil {
		t.Fatal("profile = nil, want updated blue profile")
	}
	if got.Profile.Name != "blue" || got.Profile.Active {
		t.Fatalf("profile = %+v, want inactive blue profile output", got.Profile)
	}
	if got.Profile.ClusterName != "cluster-blue" || got.Profile.OrgID != "org-42" {
		t.Fatalf("profile metadata = %+v, want API-derived metadata", got.Profile)
	}
}

func TestProfileDeleteClearsActiveProfileForSelectedEnv(t *testing.T) {
	setTestConfigHome(t)

	cfg := mustLoadConfig(t)
	cfg.ActiveEnv = "staging"
	cfg.EnvProfiles["prod"] = config.EnvProfileContainer{
		ActiveProfile: "blue",
		Profiles: map[string]config.ProfileRecord{
			"blue": {
				ClusterID: "prod-blue",
			},
		},
	}
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		ActiveProfile: "blue",
		Profiles: map[string]config.ProfileRecord{
			"blue": {
				ClusterID: "staging-blue",
			},
			"green": {
				ClusterID: "staging-green",
			},
		},
	}
	if err := cfg.Save(); err != nil {
		t.Fatalf("cfg.Save() error = %v", err)
	}

	var stdout bytes.Buffer
	if err := RunWithIO([]string{"profile", "delete", "blue"}, &stdout); err != nil {
		t.Fatalf("RunWithIO(profile delete) error = %v", err)
	}

	loaded := mustLoadConfig(t)
	stagingProfiles := loaded.EnvProfiles["staging"]
	if stagingProfiles.ActiveProfile != "" {
		t.Fatalf("EnvProfiles[staging].ActiveProfile = %q, want empty", stagingProfiles.ActiveProfile)
	}
	if _, ok := stagingProfiles.Profiles["blue"]; ok {
		t.Fatal("EnvProfiles[staging].Profiles[blue] still present after delete")
	}
	if got := loaded.EnvProfiles["prod"].ActiveProfile; got != "blue" {
		t.Fatalf("EnvProfiles[prod].ActiveProfile = %q, want %q", got, "blue")
	}
	if _, ok := loaded.EnvProfiles["prod"].Profiles["blue"]; !ok {
		t.Fatal("EnvProfiles[prod].Profiles[blue] missing, want unchanged prod profile")
	}

	var got struct {
		Env            string `json:"env"`
		ActiveProfile  string `json:"active_profile"`
		DeletedProfile string `json:"deleted_profile"`
	}
	if err := json.Unmarshal(stdout.Bytes(), &got); err != nil {
		t.Fatalf("json.Unmarshal(profile delete) error = %v\noutput=%s", err, stdout.String())
	}

	if got.Env != "staging" || got.ActiveProfile != "" || got.DeletedProfile != "blue" {
		t.Fatalf("delete output = %+v, want staging delete with cleared active profile", got)
	}

	stdout.Reset()
	if err := RunWithIO([]string{"profile", "current"}, &stdout); err != nil {
		t.Fatalf("RunWithIO(profile current after delete) error = %v", err)
	}

	var current struct {
		Env           string       `json:"env"`
		ActiveProfile string       `json:"active_profile"`
		Profile       *profileJSON `json:"profile"`
	}
	if err := json.Unmarshal(stdout.Bytes(), &current); err != nil {
		t.Fatalf("json.Unmarshal(profile current after delete) error = %v\noutput=%s", err, stdout.String())
	}
	if current.Env != "staging" || current.ActiveProfile != "" || current.Profile != nil {
		t.Fatalf("current output = %+v, want staging env with no active profile", current)
	}
}

func TestProfileOpenOpensClinicURLForActiveProfile(t *testing.T) {
	setTestConfigHome(t)

	cfg := mustLoadConfig(t)
	cfg.ActiveEnv = "staging"
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		ActiveProfile: "blue",
		Profiles: map[string]config.ProfileRecord{
			"blue": {
				ClusterID: "cluster-42",
				OrgID:     "org-42",
			},
		},
	}
	if err := cfg.Save(); err != nil {
		t.Fatalf("cfg.Save() error = %v", err)
	}

	var openedURL string
	originalOpen := openProfileURLInBrowser
	openProfileURLInBrowser = func(url string) error {
		openedURL = url
		return nil
	}
	defer func() {
		openProfileURLInBrowser = originalOpen
	}()

	var stdout bytes.Buffer
	if err := RunWithIO([]string{"profile", "open"}, &stdout); err != nil {
		t.Fatalf("RunWithIO(profile open) error = %v", err)
	}

	if got, want := openedURL, "https://staging-clinic.pingcap.com/portal/#/orgs/org-42/clusters/cluster-42"; got != want {
		t.Fatalf("opened clinic URL = %q, want %q", got, want)
	}
	if got := strings.TrimSpace(stdout.String()); got != "" {
		t.Fatalf("profile open stdout = %q, want empty output", got)
	}
}

func TestProfileOpenAllowsExplicitProfileNameWithoutSwitchingActiveProfile(t *testing.T) {
	setTestConfigHome(t)

	cfg := mustLoadConfig(t)
	cfg.ActiveEnv = "staging"
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		ActiveProfile: "green",
		Profiles: map[string]config.ProfileRecord{
			"green": {
				ClusterID: "cluster-green",
				OrgID:     "org-green",
			},
			"blue": {
				ClusterID: "cluster-blue",
				OrgID:     "org-blue",
			},
		},
	}
	if err := cfg.Save(); err != nil {
		t.Fatalf("cfg.Save() error = %v", err)
	}

	var openedURL string
	originalOpen := openProfileURLInBrowser
	openProfileURLInBrowser = func(url string) error {
		openedURL = url
		return nil
	}
	defer func() {
		openProfileURLInBrowser = originalOpen
	}()

	var stdout bytes.Buffer
	if err := RunWithIO([]string{"profile", "open", "blue"}, &stdout); err != nil {
		t.Fatalf("RunWithIO(profile open blue) error = %v", err)
	}

	if got, want := openedURL, "https://staging-clinic.pingcap.com/portal/#/orgs/org-blue/clusters/cluster-blue"; got != want {
		t.Fatalf("opened clinic URL = %q, want %q", got, want)
	}
	if got := strings.TrimSpace(stdout.String()); got != "" {
		t.Fatalf("profile open stdout = %q, want empty output", got)
	}
}

func TestProfileOpenRequiresActiveProfileWhenNoNameProvided(t *testing.T) {
	setTestConfigHome(t)

	cfg := mustLoadConfig(t)
	cfg.ActiveEnv = "staging"
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		Profiles: map[string]config.ProfileRecord{
			"blue": {
				ClusterID: "cluster-blue",
				OrgID:     "org-blue",
			},
		},
	}
	if err := cfg.Save(); err != nil {
		t.Fatalf("cfg.Save() error = %v", err)
	}

	err := RunWithIO([]string{"profile", "open"}, &bytes.Buffer{})
	if err == nil {
		t.Fatal("RunWithIO(profile open without active profile) error = nil, want validation error")
	}
	if got, want := err.Error(), "profile open requires an active profile in env staging when no profile name is provided"; got != want {
		t.Fatalf("RunWithIO(profile open without active profile) error = %q, want %q", got, want)
	}
}

func TestProfileOpenFailsWhenClinicURLIsUnavailable(t *testing.T) {
	setTestConfigHome(t)

	cfg := mustLoadConfig(t)
	cfg.ActiveEnv = "staging"
	cfg.EnvProfiles["staging"] = config.EnvProfileContainer{
		ActiveProfile: "blue",
		Profiles: map[string]config.ProfileRecord{
			"blue": {
				ClusterID: "cluster-blue",
			},
		},
	}
	if err := cfg.Save(); err != nil {
		t.Fatalf("cfg.Save() error = %v", err)
	}

	err := RunWithIO([]string{"profile", "open"}, &bytes.Buffer{})
	if err == nil {
		t.Fatal("RunWithIO(profile open without clinic_url) error = nil, want validation error")
	}
	if got, want := err.Error(), "profile open requires clinic_url for profile blue in env staging"; got != want {
		t.Fatalf("RunWithIO(profile open without clinic_url) error = %q, want %q", got, want)
	}
}

func TestProfileOpenRejectsTooManyArgs(t *testing.T) {
	setTestConfigHome(t)

	err := RunWithIO([]string{"profile", "open", "blue", "extra"}, &bytes.Buffer{})
	if err == nil {
		t.Fatal("RunWithIO(profile open with too many args) error = nil, want validation error")
	}
	if got, want := err.Error(), "accepts at most 1 arg(s), received 2"; got != want {
		t.Fatalf("RunWithIO(profile open with too many args) error = %q, want %q", got, want)
	}
}

func TestProfileSubcommandsRejectUnexpectedArgsThroughCobra(t *testing.T) {
	t.Parallel()

	testCases := []struct {
		name string
		args []string
		want string
	}{
		{name: "list extra", args: []string{"list", "extra"}, want: `unknown command "extra" for "profile list"`},
		{name: "current extra", args: []string{"current", "extra"}, want: `unknown command "extra" for "profile current"`},
		{name: "open extra", args: []string{"open", "blue", "extra"}, want: "accepts at most 1 arg(s), received 2"},
		{name: "use missing", args: []string{"use"}, want: "accepts 1 arg(s), received 0"},
		{name: "use extra", args: []string{"use", "blue", "extra"}, want: "accepts 1 arg(s), received 2"},
		{name: "set missing", args: []string{"set"}, want: "accepts 1 arg(s), received 0"},
		{name: "set extra", args: []string{"set", "blue", "extra"}, want: "accepts 1 arg(s), received 2"},
		{name: "delete missing", args: []string{"delete"}, want: "accepts 1 arg(s), received 0"},
		{name: "delete extra", args: []string{"delete", "blue", "extra"}, want: "accepts 1 arg(s), received 2"},
	}

	for _, tc := range testCases {
		tc := tc
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			err := profileCommandHandler(nil, tc.args, &bytes.Buffer{})
			if err == nil {
				t.Fatal("profileCommandHandler() error = nil, want Cobra argument validation error")
			}
			if got := err.Error(); !strings.Contains(got, tc.want) {
				t.Fatalf("profileCommandHandler() error = %q, want to contain %q", got, tc.want)
			}
		})
	}
}

func TestProfileClusterSubcommandRemoved(t *testing.T) {
	setTestConfigHome(t)

	err := RunWithIO([]string{"profile", "cluster", "list"}, &bytes.Buffer{})
	if err == nil {
		t.Fatal("RunWithIO(profile cluster list) error = nil, want unknown subcommand")
	}
	if got := err.Error(); !strings.Contains(got, "unknown profile subcommand: cluster") {
		t.Fatalf("RunWithIO(profile cluster list) error = %q, want unknown profile subcommand", got)
	}
}
