package main

import (
	"bytes"
	"os"
	"path/filepath"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/aisupport/apps/cli/operation-mcp/devops"
	"github.com/tidbcloud/aisupport/packages/sdk-go/infra/auth/consts"
)

const testOperationsYAML = `
- name: RestartChangefeed
  alias: Restart Changefeed
  target: undefined
  description: restart a changefeed
  categories: ["cdc-meta"]
  actions:
  - name: RestartChangefeed
    preferStartPolicy: manual
  params:
    changefeed_id:
      type: string
    cluster_type:
      type: string
  approval:
    nodes:
    - userGroup: cloud_ticdc_operation
      method: ANY
`

func writeOperationsFile(t *testing.T) string {
	t.Helper()

	path := filepath.Join(t.TempDir(), "operations.yaml")
	require.NoError(t, os.WriteFile(path, []byte(testOperationsYAML), 0o600))
	return path
}

func clearAuthEnv(t *testing.T) {
	t.Helper()

	t.Setenv(consts.EnvDevOpsAccessToken, "")
	t.Setenv(consts.EnvDevOpsAPIToken, "")
	t.Setenv(consts.EnvDevOpsAPIKey, "")
}

func runRoot(t *testing.T, args ...string) (string, error) {
	t.Helper()

	root := NewRootCommand()
	var stdout bytes.Buffer
	root.SetOut(&stdout)
	root.SetErr(&stdout)
	root.SetArgs(args)

	err := root.Execute()
	return stdout.String(), err
}

func TestDefaultAllowlistIsRestartChangefeedOnly(t *testing.T) {
	require.Equal(t, []string{"RestartChangefeed"}, defaultAllowedOperations)
}

func TestResolveEndpointsPerEnvironment(t *testing.T) {
	for env, want := range map[string][2]string{
		"prod":    {"https://prod.devops.pingcap.com", "https://ops.tidbcloud.com"},
		"staging": {"https://staging.devops.pingcap.com", "https://ops-staging.tidbcloud.com"},
		"dev":     {"https://dev.devops.pingcap.com", "https://ops-dev.tidbcloud.com"},
	} {
		base, portal, err := (&options{env: env}).resolveEndpoints()
		require.NoError(t, err)
		require.Equal(t, want[0], base, env)
		require.Equal(t, want[1], portal, env)
	}
}

func TestResolveEndpointsFlagsWin(t *testing.T) {
	base, portal, err := (&options{
		env:          "prod",
		baseURL:      "http://devops.local",
		opsPortalURL: "http://ops.local",
	}).resolveEndpoints()
	require.NoError(t, err)
	require.Equal(t, "http://devops.local", base)
	require.Equal(t, "http://ops.local", portal)
}

func TestResolveEndpointsRejectsUnknownEnv(t *testing.T) {
	_, _, err := (&options{env: "qa"}).resolveEndpoints()
	require.ErrorContains(t, err, `unknown env "qa"`)
	require.ErrorContains(t, err, string(devops.EnvProd))
}

func TestRootRequiresDevOpsCredential(t *testing.T) {
	clearAuthEnv(t)

	out, err := runRoot(t, "--operations-file", writeOperationsFile(t), "tools")
	require.Error(t, err)
	require.ErrorContains(t, err, consts.EnvDevOpsAccessToken)
	require.ErrorContains(t, err, consts.EnvDevOpsAPIToken)
	require.ErrorContains(t, err, consts.EnvDevOpsAPIKey)
	require.Empty(t, out)
	require.Contains(t, NewRootCommand().Long, consts.EnvDevOpsAPIKey)
}

func TestToolsCommandReadsCatalogFromFile(t *testing.T) {
	clearAuthEnv(t)
	t.Setenv(consts.EnvDevOpsAPIToken, "test-token")

	out, err := runRoot(t, "--operations-file", writeOperationsFile(t), "--enable-write", "tools")
	require.NoError(t, err)
	require.Contains(t, out, "submit_restart_changefeed")
	require.Contains(t, out, "submit_operation")
	require.Contains(t, out, "get_operation_instance")
}

func TestToolsCommandIsReadOnlyByDefault(t *testing.T) {
	clearAuthEnv(t)
	t.Setenv(consts.EnvDevOpsAPIToken, "test-token")

	out, err := runRoot(t, "--operations-file", writeOperationsFile(t), "tools")
	require.NoError(t, err)
	require.NotContains(t, out, "submit_restart_changefeed")
	require.NotContains(t, out, "submit_operation")
	require.Contains(t, out, "preview_operation")
}

func TestToolsCommandRejectsUnknownAllowlistEntry(t *testing.T) {
	clearAuthEnv(t)
	t.Setenv(consts.EnvDevOpsAPIToken, "test-token")

	_, err := runRoot(t,
		"--operations-file", writeOperationsFile(t),
		"--allow", "RestartEverything",
		"--enable-write",
		"tools",
	)
	require.ErrorContains(t, err, "RestartEverything")
}
