package auth

import (
	"context"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/require"
	"golang.org/x/oauth2"
)

func TestConfidentialOIDCOpaqueTokenIdentity(t *testing.T) {
	const owner = "did:plc:abcdefghijklmnopqrstuvwx"
	for _, subject := range []string{owner, "did:plc:someoneelse"} {
		t.Run(subject, func(t *testing.T) {
			server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				w.Header().Set("Content-Type", "application/json")
				switch r.URL.Path {
				case "/token":
					id, secret, ok := r.BasicAuth()
					require.True(t, ok)
					require.Equal(t, "client", id)
					require.Equal(t, "secret", secret)
					require.Equal(t, "authorization_code", r.FormValue("grant_type"))
					require.Equal(t, "code", r.FormValue("code"))
					// An ID token must not override the authenticated userinfo identity.
					w.Write([]byte(`{"access_token":"private-opaque-token","token_type":"Bearer","id_token":"untrusted-id-token"}`))
				case "/userinfo":
					require.Equal(t, "Bearer private-opaque-token", r.Header.Get("Authorization"))
					w.Write([]byte(`{"sub":"` + subject + `"}`))
				default:
					http.NotFound(w, r)
				}
			}))
			defer server.Close()
			p := &oidcProvider{oauth2: oauth2.Config{ClientID: "client", ClientSecret: "secret", Endpoint: oauth2.Endpoint{TokenURL: server.URL + "/token", AuthStyle: oauth2.AuthStyleInHeader}}, userInfoURL: server.URL + "/userinfo", userIDField: "/sub", allowedUsers: []string{owner}}
			ctx := context.WithValue(context.Background(), oauth2.HTTPClient, server.Client())
			c, engine := gin.CreateTestContext(httptest.NewRecorder())
			engine.ContextWithFallback = true
			c.Request = httptest.NewRequest("GET", "https://gateway/callback?state=random-state&code=code", nil).WithContext(ctx)
			token, err := p.Exchange(c, "random-state")
			require.NoError(t, err)
			allowed, user, _, err := p.Authorization(ctx, token)
			require.NoError(t, err)
			require.Equal(t, subject, user)
			require.Equal(t, subject == owner, allowed)
		})
	}
}
