package domain

import (
	"reflect"
	"testing"
)

func TestHydraClient_HeadlessLoginFlags(t *testing.T) {
	t.Run("metadata-backed headless login client is supported", func(t *testing.T) {
		client := HydraClient{
			TokenEndpointAuthMethod: "none",
			Metadata: map[string]any{
				"headless_login_enabled":              true,
				"headless_token_endpoint_auth_method": "private_key_jwt",
				"headless_jwks_uri":                   "https://rp.example.com/.well-known/jwks.json",
			},
		}

		if !client.SupportsHeadlessLogin() {
			t.Fatalf("expected metadata-backed headless login client")
		}
		if !client.IsHeadlessLoginEnabled() {
			t.Fatalf("expected metadata-backed headless login enabled")
		}
	})

	t.Run("inline jwks without jwks uri does not support headless login", func(t *testing.T) {
		client := HydraClient{
			TokenEndpointAuthMethod: "private_key_jwt",
			JWKS: map[string]any{
				"keys": []map[string]any{{
					"kty": "RSA",
				}},
			},
			Metadata: map[string]any{
				"headless_login_enabled": true,
			},
		}

		if client.SupportsHeadlessLogin() {
			t.Fatalf("expected headless login prerequisites to be missing")
		}
		if client.IsHeadlessLoginEnabled() {
			t.Fatalf("expected headless login disabled without jwks uri")
		}
	})

	t.Run("jwks uri without private_key_jwt does not support headless login", func(t *testing.T) {
		client := HydraClient{
			TokenEndpointAuthMethod: "none",
			JWKSUri:                 "https://rp.example.com/.well-known/jwks.json",
			Metadata: map[string]any{
				"headless_login_enabled": true,
			},
		}

		if client.SupportsHeadlessLogin() {
			t.Fatalf("expected headless login prerequisites to be missing")
		}
		if client.IsHeadlessLoginEnabled() {
			t.Fatalf("expected headless login disabled when prerequisites are missing")
		}
	})

	t.Run("headless login client without boolean metadata flag is not enabled", func(t *testing.T) {
		client := HydraClient{
			TokenEndpointAuthMethod: "private_key_jwt",
			JWKSUri:                 "https://rp.example.com/.well-known/jwks.json",
			Metadata: map[string]any{
				"headless_login_enabled": "true",
			},
		}

		if !client.SupportsHeadlessLogin() {
			t.Fatalf("expected headless login client")
		}
		if client.IsHeadlessLoginEnabled() {
			t.Fatalf("expected headless login disabled for non-bool metadata")
		}
	})
}

func TestHydraClientHeadlessMetadataAccessors(t *testing.T) {
	t.Run("metadata values override inline values", func(t *testing.T) {
		metadataJWKS := map[string]any{"keys": []any{"metadata-key"}}
		client := HydraClient{
			TokenEndpointAuthMethod: "client_secret_post",
			JWKSUri:                 "https://inline.example.com/jwks.json",
			JWKS:                    map[string]any{"keys": []any{"inline-key"}},
			Metadata: map[string]any{
				MetadataHeadlessTokenEndpointAuthMethod: " private_key_jwt ",
				MetadataHeadlessJWKSURI:                 " https://metadata.example.com/jwks.json ",
				MetadataHeadlessJWKS:                    metadataJWKS,
			},
		}

		if got := client.HeadlessTokenEndpointAuthMethod(); got != "private_key_jwt" {
			t.Fatalf("unexpected auth method: %q", got)
		}
		if got := client.HeadlessJWKSURI(); got != "https://metadata.example.com/jwks.json" {
			t.Fatalf("unexpected jwks uri: %q", got)
		}
		if got := client.HeadlessJWKS(); !reflect.DeepEqual(got, metadataJWKS) {
			t.Fatalf("unexpected jwks value: %#v", got)
		}
	})

	t.Run("blank or missing metadata values fall back to inline values", func(t *testing.T) {
		inlineJWKS := map[string]any{"keys": []any{"inline-key"}}
		client := HydraClient{
			TokenEndpointAuthMethod: " private_key_jwt ",
			JWKSUri:                 " https://inline.example.com/jwks.json ",
			JWKS:                    inlineJWKS,
			Metadata: map[string]any{
				MetadataHeadlessTokenEndpointAuthMethod: " ",
				MetadataHeadlessJWKSURI:                 " ",
				MetadataHeadlessJWKS:                    nil,
			},
		}

		if got := client.HeadlessTokenEndpointAuthMethod(); got != "private_key_jwt" {
			t.Fatalf("unexpected auth method: %q", got)
		}
		if got := client.HeadlessJWKSURI(); got != "https://inline.example.com/jwks.json" {
			t.Fatalf("unexpected jwks uri: %q", got)
		}
		if got := client.HeadlessJWKS(); !reflect.DeepEqual(got, inlineJWKS) {
			t.Fatalf("unexpected jwks value: %#v", got)
		}
	})
}

func TestHydraClientBackchannelLogoutAccessors(t *testing.T) {
	t.Run("metadata values override inline values", func(t *testing.T) {
		inlineRequired := false
		client := HydraClient{
			BackChannelLogoutURI:             "https://inline.example.com/logout",
			BackChannelLogoutSessionRequired: &inlineRequired,
			Metadata: map[string]any{
				MetadataBackChannelLogoutURI:             " https://metadata.example.com/logout ",
				MetadataBackChannelLogoutSessionRequired: true,
			},
		}

		if got := client.BackchannelLogoutURI(); got != "https://metadata.example.com/logout" {
			t.Fatalf("unexpected logout uri: %q", got)
		}
		if !client.BackchannelLogoutSessionRequiredValue() {
			t.Fatalf("expected metadata session_required value")
		}
	})

	t.Run("blank or missing metadata values fall back to inline values", func(t *testing.T) {
		inlineRequired := true
		client := HydraClient{
			BackChannelLogoutURI:             " https://inline.example.com/logout ",
			BackChannelLogoutSessionRequired: &inlineRequired,
			Metadata: map[string]any{
				MetadataBackChannelLogoutURI:             " ",
				MetadataBackChannelLogoutSessionRequired: "true",
			},
		}

		if got := client.BackchannelLogoutURI(); got != "https://inline.example.com/logout" {
			t.Fatalf("unexpected logout uri: %q", got)
		}
		if !client.BackchannelLogoutSessionRequiredValue() {
			t.Fatalf("expected inline session_required value")
		}
	})

	t.Run("missing session required defaults to false", func(t *testing.T) {
		client := HydraClient{}

		if got := client.BackchannelLogoutURI(); got != "" {
			t.Fatalf("unexpected logout uri: %q", got)
		}
		if client.BackchannelLogoutSessionRequiredValue() {
			t.Fatalf("expected default session_required false")
		}
	})
}
