package ones_test

import (
	"context"
	"crypto/tls"
	"net/http"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/extension"
	"github.com/tidbcloud/AgentTeam/internal/extension/bootstrap"
	"github.com/tidbcloud/AgentTeam/internal/extension/providers/ones"
	"github.com/tidbcloud/AgentTeam/internal/extension/registry"
	"github.com/tidbcloud/AgentTeam/internal/extension/runner"
	appregistry "github.com/tidbcloud/AgentTeam/internal/store/app/registry"
	"github.com/tidbcloud/AgentTeam/internal/store/model"
)

type staticCredentialSource struct {
	credentials runner.Credentials
}

func (source staticCredentialSource) ResolveProviderCredentials(
	context.Context, string, string,
) (runner.Credentials, error) {
	return source.credentials, nil
}

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

	extensionUnit, err := ones.Extension(staticCredentialSource{})
	require.NoError(t, err)

	names := make([]string, 0)
	for _, action := range extensionUnit.Definition.Actions {
		names = append(names, action.Name)
	}
	lister, ok := extensionUnit.Implementation.Executor.(runner.ActionLister)
	require.True(t, ok)
	require.ElementsMatch(t, names, lister.ActionNames())

	require.Equal(t, "ones-rest-v1", extensionUnit.Implementation.Revision)
	require.Equal(t, appregistry.OnesAppID, extensionUnit.Distribution.AppID)
	require.Equal(t, appregistry.OnesAppSlug, extensionUnit.Distribution.AppSlug)
	require.True(t, appregistry.IsProductApp(
		extensionUnit.Distribution.AppID, extensionUnit.Distribution.AppSlug))
	require.NoError(t, bootstrap.Register(registry.New(), []extension.Extension{extensionUnit}))
}

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

	extensionUnit, err := ones.Extension(staticCredentialSource{})
	require.NoError(t, err)
	reg := registry.New()
	require.NoError(t, bootstrap.Register(reg, []extension.Extension{extensionUnit}))
	entry, ok := reg.LookupByIdentity(ones.Domain, 1)
	require.True(t, ok)
	require.Equal(t, model.OnesBuiltinExtensionDefinitionDigest, entry.Definition.Digest)
}

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

	spec := ones.AuthSpec()
	require.Equal(t, runner.AuthHeaders, spec.Kind)
	require.NoError(t, spec.Validate(runner.Credentials{
		"base_url": "https://ones.example.com",
		"user_id":  "DU6krHBN",
		"token":    "tok",
	}))
	for _, field := range spec.Fields {
		switch field.Name {
		case "base_url":
			require.Empty(t, field.HeaderName)
		case "user_id":
			require.Equal(t, "Ones-User-Id", field.HeaderName)
		case "token":
			require.Equal(t, "Ones-Auth-Token", field.HeaderName)
			require.True(t, field.Secret)
		}
	}
}

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

	err := ones.ValidateCredentials(context.Background(), runner.Credentials{
		"base_url": "http://insecure.example.com",
		"user_id":  "DU6krHBN",
		"token":    "tok",
	})
	require.Error(t, err)

	err = ones.ValidateCredentials(context.Background(), runner.Credentials{
		"user_id": "DU6krHBN",
		"token":   "tok",
	})
	require.Equal(t, runner.ErrorConnectionUnavailable, runner.CodeOf(err))
}

func insecureTransport() *http.Transport {
	return &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
}
