package com.jovan.assistant.ui import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.GraphicEq import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableLongStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp import com.jovan.assistant.data.FirebaseRepo import kotlinx.coroutines.launch private const val MAX_FAILS = 3 private const val COOLDOWN_MS = 30_000L @Composable fun AuthScreen() { val scope = rememberCoroutineScope() var registering by remember { mutableStateOf(false) } var email by remember { mutableStateOf("") } var password by remember { mutableStateOf("") } var confirm by remember { mutableStateOf("") } var error by remember { mutableStateOf(null) } var loading by remember { mutableStateOf(false) } var fails by remember { mutableIntStateOf(0) } var lockedUntil by remember { mutableLongStateOf(0L) } Column( Modifier.fillMaxSize().imePadding().verticalScroll(rememberScrollState()).padding(28.dp), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { Icon(Icons.Filled.GraphicEq, null, Modifier.size(56.dp), tint = MaterialTheme.colorScheme.primary) Spacer(Modifier.height(12.dp)) Text("AI Voice Assistant", style = MaterialTheme.typography.headlineMedium) Text( if (registering) "Create your account" else "Sign in to continue", color = MaterialTheme.colorScheme.onSurfaceVariant ) Spacer(Modifier.height(28.dp)) OutlinedTextField( email, { email = it }, label = { Text("Email") }, singleLine = true, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email), modifier = Modifier.fillMaxWidth() ) Spacer(Modifier.height(12.dp)) OutlinedTextField( password, { password = it }, label = { Text("Password") }, singleLine = true, visualTransformation = PasswordVisualTransformation(), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), modifier = Modifier.fillMaxWidth() ) if (registering) { Spacer(Modifier.height(12.dp)) OutlinedTextField( confirm, { confirm = it }, label = { Text("Confirm password") }, singleLine = true, visualTransformation = PasswordVisualTransformation(), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), modifier = Modifier.fillMaxWidth() ) } error?.let { Spacer(Modifier.height(12.dp)) Text(it, color = MaterialTheme.colorScheme.error, style = MaterialTheme.typography.bodyMedium) } Spacer(Modifier.height(20.dp)) Button( onClick = { val now = System.currentTimeMillis() if (now < lockedUntil) { error = "Too many attempts. Try again in ${(lockedUntil - now) / 1000 + 1}s." return@Button } if (email.isBlank() || password.length < 6) { error = "Enter a valid email and a password of at least 6 characters." return@Button } if (registering && password != confirm) { error = "Passwords don't match." return@Button } loading = true; error = null scope.launch { try { if (registering) FirebaseRepo.register(email, password) else FirebaseRepo.login(email, password) fails = 0 } catch (e: Exception) { fails++ if (fails >= MAX_FAILS) { lockedUntil = System.currentTimeMillis() + COOLDOWN_MS fails = 0 } error = e.localizedMessage ?: "Authentication failed." } finally { loading = false } } }, enabled = !loading, modifier = Modifier.fillMaxWidth().height(52.dp) ) { if (loading) CircularProgressIndicator(Modifier.size(22.dp), strokeWidth = 2.dp) else Text(if (registering) "Create account" else "Sign in") } TextButton(onClick = { registering = !registering; error = null }) { Text(if (registering) "Already have an account? Sign in" else "New here? Create an account") } } }