package com.estateunified.panel import java.util.UUID import java.util.concurrent.ConcurrentHashMap internal data class OtpRequest( val requestId: String, val phone: String, val createdAtMs: Long, ) internal class OtpStore( val acceptedCode: String = System.getenv("PANEL_OTP_CODE")?.ifBlank { null } ?: "0000", private val ttlMs: Long = 5 * 60 * 1000L, ) { private val requests = ConcurrentHashMap() fun create(phone: String): OtpRequest { val req = OtpRequest( requestId = UUID.randomUUID().toString(), phone = normalizePhone(phone), createdAtMs = System.currentTimeMillis(), ) requests[req.requestId] = req cleanup() return req } fun verify( phone: String, code: String, ): Boolean { cleanup() if (code.trim() != acceptedCode) return false val norm = normalizePhone(phone) return requests.values.any { it.phone == norm } } private fun normalizePhone(phone: String): String { val trimmed = phone.trim() if (!trimmed.startsWith("+")) return trimmed return "+" + trimmed.drop(1).replace("\\s+".toRegex(), "") } private fun cleanup() { val now = System.currentTimeMillis() val expired = requests.values.filter { now - it.createdAtMs > ttlMs }.map { it.requestId } expired.forEach { requests.remove(it) } } }