package gittransport

import (
	"net/http"
	"sync"
	"testing"

	"github.com/go-git/go-git/v5/plumbing/transport"
	gitclient "github.com/go-git/go-git/v5/plumbing/transport/client"
	"github.com/stretchr/testify/require"
)

func TestRegisterUsesFixedSchemeWithoutReplacingHTTP(t *testing.T) {
	ordinaryHTTP := gitclient.Protocols["http"]
	baseURL, unregister, err := Register(http.NotFoundHandler())
	require.NoError(t, err)
	require.Regexp(t, `^meshxags://[0-9a-f]+\.embedded\.invalid$`, baseURL)
	require.Same(t, ordinaryHTTP, gitclient.Protocols["http"])
	require.NotNil(t, gitclient.Protocols[protocol])
	unregister()
	require.NotNil(t, gitclient.Protocols[protocol], "fixed protocol must never be uninstalled")
}

func TestRegisterRejectsNilHandler(t *testing.T) {
	_, _, err := Register(nil)
	require.Error(t, err)
}

func TestValidateRegisteredBaseURLRejectsUncontrolledOrDecoratedEndpoints(t *testing.T) {
	baseURL, unregister, err := Register(http.NotFoundHandler())
	require.NoError(t, err)
	require.NoError(t, ValidateRegisteredBaseURL(baseURL))

	for _, invalid := range []string{
		"http://example.test",
		"meshxags://user@" + baseURL[len("meshxags://"):],
		baseURL + ":443",
		baseURL + "/existing/path",
		baseURL + "?query=value",
		baseURL + "?",
		baseURL + "#fragment",
		"meshxags://unregistered.embedded.invalid",
	} {
		require.Error(t, ValidateRegisteredBaseURL(invalid), invalid)
	}

	unregister()
	require.ErrorContains(t, ValidateRegisteredBaseURL(baseURL), "not registered")
}

func TestRegistryIsSafeDuringConcurrentGitLookupAndRuntimeChurn(t *testing.T) {
	const iterations = 100
	var wg sync.WaitGroup
	for range 8 {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for range iterations {
				_, unregister, err := Register(http.NotFoundHandler())
				require.NoError(t, err)
				unregister()
			}
		}()
		wg.Add(1)
		go func() {
			defer wg.Done()
			for range iterations {
				_, err := gitclient.NewClient(&transport.Endpoint{Protocol: protocol})
				require.NoError(t, err)
				_, err = gitclient.NewClient(&transport.Endpoint{Protocol: "http"})
				require.NoError(t, err)
			}
		}()
	}
	wg.Wait()
}
