package domain

import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"strings"
)

// MongoDB BSON field names for auth module collections.
const (
	BSONFieldID           = "_id"
	BSONFieldTenantID     = "tenant_id"
	BSONFieldCodeHash     = "code_hash"
	BSONFieldMaxUses      = "max_uses"
	BSONFieldUsedCount    = "used_count"
	BSONFieldExpiresAt    = "expires_at"
	BSONFieldNewUsersOnly = "new_users_only"
	BSONFieldCreateAt     = "create_at"
	BSONFieldUpdateAt     = "update_at"

	BSONFieldUID                 = "uid"
	BSONFieldInviteCodeID        = "invite_code_id"
	BSONFieldAcceptTermsVersion  = "accept_terms_version"
	BSONFieldMarketingOptIn      = "marketing_opt_in"
	BSONFieldRegistrationChannel = "registration_channel"
	BSONFieldClientIP            = "client_ip"
	BSONFieldUserAgent           = "user_agent"
	BSONFieldOccurredAt          = "occurred_at"
)

const inviteConsumeLockTTLSeconds = 30

const (
	OAuthStatePrefixRegister = "reg:"
	OAuthStatePrefixLogin    = "login:"
)

// RegistrationSessionRedisKey returns the Redis key for a social registration session.
func RegistrationSessionRedisKey(sessionID string) string {
	return fmt.Sprintf("auth:register:session:%s", sessionID)
}

// LoginSessionRedisKey returns the Redis key for a social login session.
func LoginSessionRedisKey(sessionID string) string {
	return fmt.Sprintf("auth:login:session:%s", sessionID)
}

// LoginMFAChallengeRedisKey returns the Redis key for a password-login MFA challenge.
func LoginMFAChallengeRedisKey(challengeID string) string {
	return fmt.Sprintf("auth:login:mfa:%s", challengeID)
}

// NormalizeInviteCode trims and uppercases user input before hashing.
func NormalizeInviteCode(code string) string {
	return strings.ToUpper(strings.TrimSpace(code))
}

// HashInviteCode returns a stable SHA-256 hex digest for storage and lookup.
func HashInviteCode(code string) string {
	normalized := NormalizeInviteCode(code)
	sum := sha256.Sum256([]byte(normalized))
	return hex.EncodeToString(sum[:])
}

// InviteConsumeLockRedisKey returns the Redis key for serializing invite consumption.
func InviteConsumeLockRedisKey(tenantID, codeHash string) string {
	return fmt.Sprintf("auth:invite:consume:%s:%s", tenantID, codeHash)
}

// InviteConsumeLockTTLSeconds is the Redis lock TTL for Consume.
func InviteConsumeLockTTLSeconds() int {
	return inviteConsumeLockTTLSeconds
}

// JWTPairRedisKey maps an access or refresh jti to its paired jti.
func JWTPairRedisKey(jti string) string {
	return fmt.Sprintf("auth:jwt:pair:%s", jti)
}

// JWTBlacklistRedisKey marks a revoked jti until natural expiry.
func JWTBlacklistRedisKey(jti string) string {
	return fmt.Sprintf("auth:jwt:bl:%s", jti)
}
