package accounts

import (
	"testing"
	"time"
)

// ─── normalizeRole ──────────────────────────────────────────────────────────

func TestNormalizeRole_Admin(t *testing.T) {
	if got := normalizeRole("admin"); got != RoleAdmin {
		t.Fatalf("expected %q, got %q", RoleAdmin, got)
	}
}

func TestNormalizeRole_User(t *testing.T) {
	if got := normalizeRole("user"); got != RoleUser {
		t.Fatalf("expected %q, got %q", RoleUser, got)
	}
}

func TestNormalizeRole_Unknown(t *testing.T) {
	for _, input := range []string{"", "superuser", "moderator", "ADMIN"} {
		if got := normalizeRole(input); got != RoleUser {
			t.Fatalf("input %q: expected %q fallback, got %q", input, RoleUser, got)
		}
	}
}

// ─── roleFromUser ───────────────────────────────────────────────────────────

func TestRoleFromUser_Admin(t *testing.T) {
	u := User{IsAdmin: true}
	if got := roleFromUser(u); got != RoleAdmin {
		t.Fatalf("expected admin role, got %q", got)
	}
}

func TestRoleFromUser_RegularUser(t *testing.T) {
	u := User{IsAdmin: false}
	if got := roleFromUser(u); got != RoleUser {
		t.Fatalf("expected user role, got %q", got)
	}
}

// ─── GenerateTokens / ParseAccessToken / ParseRefreshToken ──────────────────

func TestGenerateAndParse_RoundTrip(t *testing.T) {
	t.Setenv("JWT_SECRET", "test-access-secret-xyz")
	t.Setenv("JWT_REFRESH_SECRET", "test-refresh-secret-xyz")

	access, refresh, err := GenerateTokens(99, RoleUser)
	if err != nil {
		t.Fatalf("GenerateTokens error: %v", err)
	}

	uid, err := ParseAccessToken(access)
	if err != nil {
		t.Fatalf("ParseAccessToken error: %v", err)
	}
	if uid != 99 {
		t.Fatalf("expected user_id 99, got %d", uid)
	}

	ruid, err := ParseRefreshToken(refresh)
	if err != nil {
		t.Fatalf("ParseRefreshToken error: %v", err)
	}
	if ruid != 99 {
		t.Fatalf("expected refresh user_id 99, got %d", ruid)
	}
}

func TestGenerateTokens_MissingSecretsError(t *testing.T) {
	t.Setenv("JWT_SECRET", "")
	t.Setenv("JWT_REFRESH_SECRET", "")

	if _, _, err := GenerateTokens(1, RoleUser); err == nil {
		t.Fatal("expected error when JWT secrets are missing")
	}
}

func TestParseAccessToken_TamperedTokenFails(t *testing.T) {
	t.Setenv("JWT_SECRET", "my-secret")
	t.Setenv("JWT_REFRESH_SECRET", "my-refresh")

	_, err := ParseAccessToken("this.is.notavalidtoken")
	if err == nil {
		t.Fatal("expected error for tampered token")
	}
}

func TestParseRefreshToken_WrongSecretFails(t *testing.T) {
	t.Setenv("JWT_SECRET", "secret-a")
	t.Setenv("JWT_REFRESH_SECRET", "secret-b")

	access, _, err := GenerateTokens(1, RoleUser)
	if err != nil {
		t.Fatalf("GenerateTokens error: %v", err)
	}

	// Access token'ı refresh secret ile parse etmeye çalışmak başarısız olmalı
	_, err = ParseRefreshToken(access)
	if err == nil {
		t.Fatal("expected error when parsing access token with refresh secret")
	}
}

// ─── parseAccessClaims – role claim içeriği ──────────────────────────────────

func TestParseAccessClaims_ContainsRole(t *testing.T) {
	t.Setenv("JWT_SECRET", "test-secret")
	t.Setenv("JWT_REFRESH_SECRET", "test-refresh")

	access, _, err := GenerateTokens(7, RoleAdmin)
	if err != nil {
		t.Fatalf("GenerateTokens error: %v", err)
	}

	claims, err := parseAccessClaims(access)
	if err != nil {
		t.Fatalf("parseAccessClaims error: %v", err)
	}

	if claims.Role != RoleAdmin {
		t.Fatalf("expected role %q, got %q", RoleAdmin, claims.Role)
	}
	if claims.UserID != 7 {
		t.Fatalf("expected user_id 7, got %d", claims.UserID)
	}
}

// ─── User model – ApiToken süresi ───────────────────────────────────────────

func TestUser_ApiTokenExpiresAt_NilMeansNeverExpires(t *testing.T) {
	u := User{ApiTokenExpiresAt: nil}
	if u.ApiTokenExpiresAt != nil {
		t.Fatal("nil ApiTokenExpiresAt must remain nil")
	}
}

func TestUser_ApiTokenExpiresAt_CanBeSet(t *testing.T) {
	exp := time.Now().Add(24 * time.Hour)
	u := User{ApiTokenExpiresAt: &exp}
	if u.ApiTokenExpiresAt == nil {
		t.Fatal("ApiTokenExpiresAt should not be nil after assignment")
	}
	if !u.ApiTokenExpiresAt.Equal(exp) {
		t.Fatalf("expected %v, got %v", exp, *u.ApiTokenExpiresAt)
	}
}

func TestUser_IsAdminDefaultFalse(t *testing.T) {
	u := User{}
	if u.IsAdmin {
		t.Fatal("zero-value User must not be admin")
	}
}
