package security

import (
	"errors"
	"strings"
	"testing"
	"time"

	"github.com/niels/banking-app/backend/internal/domain"
)

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

	manager := NewTokenManager("test-secret-with-enough-length-for-hmac", "banking-api", 15*time.Minute)
	token, err := manager.Generate(domain.User{
		ID:    "user-1",
		Email: "demo@example.com",
		Role:  "customer",
	})
	if err != nil {
		t.Fatalf("generate token: %v", err)
	}

	claims, err := manager.Verify(token)
	if err != nil {
		t.Fatalf("verify token: %v", err)
	}
	if claims.Subject != "user-1" || claims.Role != "customer" {
		t.Fatalf("unexpected claims: %+v", claims)
	}
	if !claims.HasScope(ScopeMoneyWrite) {
		t.Fatalf("expected money write scope: %+v", claims.Scopes)
	}
}

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

	manager := NewTokenManager("test-secret-with-enough-length-for-hmac", "banking-api", 15*time.Minute)
	token, err := manager.Generate(domain.User{ID: "user-1", Email: "demo@example.com", Role: "customer"})
	if err != nil {
		t.Fatalf("generate token: %v", err)
	}

	replacement := "x"
	if strings.HasSuffix(token, "x") {
		replacement = "y"
	}
	tampered := token[:len(token)-1] + replacement
	if _, err := manager.Verify(tampered); !errors.Is(err, domain.ErrUnauthorized) {
		t.Fatalf("expected unauthorized error, got %v", err)
	}
}

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

	manager := NewTokenManager("test-secret-with-enough-length-for-hmac", "banking-api", -time.Minute)
	token, err := manager.Generate(domain.User{ID: "user-1", Email: "demo@example.com", Role: "customer"})
	if err != nil {
		t.Fatalf("generate token: %v", err)
	}

	if _, err := manager.Verify(token); !errors.Is(err, domain.ErrUnauthorized) {
		t.Fatalf("expected unauthorized error, got %v", err)
	}
}
