package extensionflow

import (
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/extension/egress"
	"github.com/tidbcloud/AgentTeam/internal/extension/spec"
)

func TestResolveProviderCredentialOAuthRequiresExactScopesAndExpiry(t *testing.T) {
	now := time.Date(2026, 8, 11, 8, 0, 0, 0, time.UTC)
	profile := &spec.AuthProfile{ID: "oauth", Type: "oauth2_bearer"}
	requirement := &spec.ActionAuthRequirement{
		Profile: "oauth", RequiredScopes: []string{"issues:read"},
	}

	resolved, oauth, expired, err := resolveProviderCredential(
		profile,
		requirement,
		[]byte(`{
			"accessToken":"access-secret",
			"refreshToken":"refresh-secret",
			"scopes":["repo","issues:read"],
			"expiresAt":"2026-08-11T08:05:00Z"
		}`),
		now,
	)
	require.NoError(t, err)
	require.False(t, expired)
	require.Equal(t, egress.CredentialOAuth2Bearer, resolved.Type)
	require.Equal(t, "access-secret", resolved.Value)
	require.Equal(t, []string{"issues:read", "repo"}, oauth.Scopes)
	require.Equal(t, "refresh-secret", oauth.RefreshToken)

	_, _, _, err = resolveProviderCredential(
		profile,
		requirement,
		[]byte(`{"accessToken":"x","scopes":["repo"]}`),
		now,
	)
	require.ErrorContains(t, err, "missing required scope")

	_, _, expired, err = resolveProviderCredential(
		profile,
		requirement,
		[]byte(`{
			"accessToken":"expired",
			"refreshToken":"refresh-secret",
			"scopes":["issues:read"],
			"expiresAt":"2026-08-11T07:59:59Z"
		}`),
		now,
	)
	require.NoError(t, err)
	require.True(t, expired)
}

func TestResolveProviderCredentialRejectsAmbiguousOrUnknownCredentialJSON(t *testing.T) {
	profile := &spec.AuthProfile{ID: "oauth", Type: "oauth2_bearer"}
	requirement := &spec.ActionAuthRequirement{Profile: "oauth"}

	for _, raw := range []string{
		`{"accessToken":"x","scopes":[],"tokenUrl":"https://attacker.invalid"}`,
		`{"accessToken":"x","scopes":["repo","repo"]}`,
		`{"accessToken":"x","scopes":[" repo"]}`,
		`{"accessToken":"x","scopes":[]} {}`,
	} {
		_, _, _, err := resolveProviderCredential(
			profile,
			requirement,
			[]byte(raw),
			time.Now().UTC(),
		)
		require.Error(t, err, raw)
	}
}

func TestResolveProviderCredentialAPIKeyUsesDefinitionPlacement(t *testing.T) {
	profile := &spec.AuthProfile{
		ID: "key", Type: "api_key", In: "header", Name: "X-Provider-Key",
	}
	requirement := &spec.ActionAuthRequirement{Profile: "key"}

	resolved, _, expired, err := resolveProviderCredential(
		profile,
		requirement,
		[]byte(`{"value":"api-secret"}`),
		time.Now().UTC(),
	)
	require.NoError(t, err)
	require.False(t, expired)
	require.Equal(t, egress.Credential{
		Type: "api_key", In: "header", Name: "X-Provider-Key", Value: "api-secret",
	}, resolved)
}

func TestResolveProviderCredentialAcceptsLegacyConnectOAuthFieldNames(t *testing.T) {
	profile := &spec.AuthProfile{ID: "oauth", Type: "oauth2_bearer"}
	requirement := &spec.ActionAuthRequirement{
		Profile: "oauth", RequiredScopes: []string{"repo"},
	}
	resolved, oauth, _, err := resolveProviderCredential(
		profile,
		requirement,
		[]byte(`{
			"access_token":"legacy-access",
			"refresh_token":"legacy-refresh",
			"scope":"repo issues:read",
			"expires_at":"2026-08-11T10:00:00Z"
		}`),
		time.Date(2026, 8, 11, 9, 0, 0, 0, time.UTC),
	)
	require.NoError(t, err)
	require.Equal(t, "legacy-access", resolved.Value)
	require.Equal(t, "legacy-refresh", oauth.RefreshToken)
	require.Equal(t, []string{"issues:read", "repo"}, oauth.Scopes)
}
