package tenants

import (
	"context"
	"path/filepath"
	"reflect"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestDedicatedSelector(t *testing.T) {
	got := dedicatedSelector([]string{"tidbcloud", "staging-tidbcloud"})
	want := "observability.pingcap.com/bizType in (tidbcloud,staging-tidbcloud)"
	assert.Equal(t, want, got)
}

func TestEntriesFromKubectlJSON(t *testing.T) {
	payload := []byte(`{
  "items": [
    {
      "metadata": {"labels": {"observability.pingcap.com/bizType": "tidbcloud"}},
      "spec": {"victoriaAccount": {"accountID": "1001", "projectID": "0"}}
    },
    {
      "metadata": {"labels": {"observability.pingcap.com/bizType": "tidbcloud"}},
      "spec": {"victoriaAccount": {"accountID": 1002, "projectID": 0}}
    },
    {
      "metadata": {"labels": {"observability.pingcap.com/bizType": "staging-tidbcloud"}},
      "spec": {"victoriaAccount": {"accountID": "1003"}}
    },
    {
      "metadata": {"labels": {"some-other-label": "x"}},
      "spec": {"victoriaAccount": {"accountID": "1004"}}
    },
    {
      "metadata": {"labels": {"observability.pingcap.com/bizType": "tidbcloud"}},
      "spec": {"victoriaAccount": {"accountID": "1001", "projectID": "0"}}
    }
  ]
}`)
	bizTypes := []string{"tidbcloud", "staging-tidbcloud"}
	got, err := EntriesFromKubectlJSON(payload, bizTypes)
	assert.NoError(t, err)
	want := []Entry{
		{Tenant: "1001:0", BizType: "tidbcloud", Source: SourceK8s},
		{Tenant: "1002:0", BizType: "tidbcloud", Source: SourceK8s},
		{Tenant: "1003:0", BizType: "staging-tidbcloud", Source: SourceK8s},
	}
	assert.True(t, reflect.DeepEqual(got, want), "got %+v want %+v", got, want)
}

func TestEntriesFromKubectlJSONBadPayload(t *testing.T) {
	_, err := EntriesFromKubectlJSON([]byte(`{not json`), DedicatedBizTypes)
	assert.Error(t, err, "expected parse error")
}

func TestNormalizeID(t *testing.T) {
	f := func(in any, want string) {
		t.Helper()
		assert.Equal(t, want, normalizeID(in), "normalizeID(%v %T)", in, in)
	}
	f("1001", "1001")
	f("  1001  ", "1001")
	f(float64(1001), "1001")
	f(float64(0), "0")
	f(nil, "")
	f(true, "") // unsupported type
	f(1.5, "1.5")
}

func TestRelPathsSinceCutoff(t *testing.T) {
	bizType := "tidbcloud"
	now := time.Now().UTC()
	objects := []ArchiveObject{
		{Key: "archived/tidbcloud/o1/p1/c1/cluster.yaml", LastModified: now.Add(-1 * 24 * time.Hour)},
		{Key: "archived/tidbcloud/o2/p2/c2/cluster.yaml", LastModified: now.Add(-100 * 24 * time.Hour)},
		{Key: "archived/other-biz/o3/p3/c3/cluster.yaml", LastModified: now},
	}
	cutoff := now.Add(-30 * 24 * time.Hour)
	got := relPathsSinceCutoff(bizType, objects, cutoff)
	want := map[string]bool{
		"o1/p1/c1/cluster.yaml": true,
	}
	assert.True(t, reflect.DeepEqual(got, want), "got %#v want %#v", got, want)
}

func TestKubectlShellListerList(t *testing.T) {
	dir := t.TempDir()
	argsFile := filepath.Join(dir, "args")
	putOnPATH(t, "kubectl", recordArgs(argsFile)+`cat <<'EOF'
{"items":[
 {"metadata":{"labels":{"observability.pingcap.com/bizType":"tidbcloud"}},
  "spec":{"victoriaAccount":{"accountID":"1001","projectID":"0"}}}
]}
EOF`)

	payload, err := NewKubectlShellLister().List(context.Background(), dedicatedSelector(DedicatedBizTypes))
	assert.NoError(t, err)
	assert.Equal(t, []string{
		"get", "clusters", "-A", "-l",
		"observability.pingcap.com/bizType in (tidbcloud,staging-tidbcloud,dev-tidbcloud)",
		"-o", "json",
	}, readArgs(t, argsFile))

	entries, err := EntriesFromKubectlJSON(payload, DedicatedBizTypes)
	assert.NoError(t, err)
	want := []Entry{{Tenant: "1001:0", BizType: "tidbcloud", Source: SourceK8s}}
	assert.True(t, reflect.DeepEqual(entries, want), "got %+v want %+v", entries, want)
}

func TestKubectlShellListerListFailure(t *testing.T) {
	putOnPATH(t, "kubectl", `echo "connection refused" 1>&2; exit 1`)
	_, err := NewKubectlShellLister().List(context.Background(), "sel")
	assert.ErrorContains(t, err, "kubectl get clusters")
	assert.ErrorContains(t, err, "connection refused")
}
