package platform

import (
	"encoding/base64"
	"encoding/json"
	"testing"
)

// makeJWT builds a syntactically valid (unsigned) JWT carrying the given claims.
// UserFromToken never verifies the signature, so a dummy header + sig suffice.
func makeJWT(claims map[string]any) string {
	payload, _ := json.Marshal(claims)
	seg := base64.RawURLEncoding.EncodeToString(payload)
	return "eyJhbGciOiJSUzI1NiJ9." + seg + ".sig"
}

func TestUserFromTokenPrefersIDToken(t *testing.T) {
	idTok := makeJWT(map[string]any{"sub": "u-1", "preferred_username": "alice"})
	accessTok := makeJWT(map[string]any{"sub": "u-1", "name": "bob"})

	u, err := UserFromToken(idTok, accessTok)
	if err != nil {
		t.Fatalf("UserFromToken: %v", err)
	}
	if u.ID != "u-1" {
		t.Errorf("id: got %q, want u-1", u.ID)
	}
	if u.Name != "alice" {
		t.Errorf("name should come from id_token preferred_username, got %q", u.Name)
	}
}

func TestUserFromTokenNamePriority(t *testing.T) {
	cases := []struct {
		name   string
		claims map[string]any
		want   string
	}{
		{"preferred_username wins", map[string]any{"sub": "s", "preferred_username": "p", "name": "n", "email": "e"}, "p"},
		{"name when no preferred", map[string]any{"sub": "s", "name": "n", "email": "e"}, "n"},
		{"email when no name", map[string]any{"sub": "s", "email": "e@x"}, "e@x"},
		{"sub as last resort", map[string]any{"sub": "s"}, "s"},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			u, err := UserFromToken(makeJWT(c.claims), "")
			if err != nil {
				t.Fatalf("UserFromToken: %v", err)
			}
			if u.Name != c.want {
				t.Errorf("name: got %q, want %q", u.Name, c.want)
			}
		})
	}
}

func TestUserFromTokenAvatarPriority(t *testing.T) {
	u, _ := UserFromToken(makeJWT(map[string]any{
		"sub": "s", "avatar": "a.png", "picture": "p.png",
	}), "")
	if u.Avatar != "a.png" {
		t.Errorf("avatar should prefer 'avatar' claim, got %q", u.Avatar)
	}

	u2, _ := UserFromToken(makeJWT(map[string]any{"sub": "s", "picture": "p.png"}), "")
	if u2.Avatar != "p.png" {
		t.Errorf("avatar should fall back to 'picture', got %q", u2.Avatar)
	}

	u3, _ := UserFromToken(makeJWT(map[string]any{"sub": "s"}), "")
	if u3.Avatar != "" {
		t.Errorf("avatar should be empty when no claim, got %q", u3.Avatar)
	}
}

func TestUserFromTokenFallsBackToAccessToken(t *testing.T) {
	accessTok := makeJWT(map[string]any{"sub": "u-9", "name": "carol"})
	u, err := UserFromToken("", accessTok)
	if err != nil {
		t.Fatalf("UserFromToken: %v", err)
	}
	if u.ID != "u-9" || u.Name != "carol" {
		t.Errorf("fallback to access_token failed: %+v", u)
	}
}

func TestUserFromTokenRejectsGarbage(t *testing.T) {
	if _, err := UserFromToken("not-a-jwt", ""); err == nil {
		t.Error("expected error for non-JWT token")
	}
	if _, err := UserFromToken("a.!!!notbase64!!!.c", ""); err == nil {
		t.Error("expected error for undecodable payload")
	}
}
