package com.peachpasswords.autofill import com.peachpasswords.shared.getDisplayDomain import com.peachpasswords.vault.VaultEntry import com.peachpasswords.vault.isLogin internal data class AutofillSaveDraft( val origin: String, val isWebOrigin: Boolean, val identity: String?, val identityIsEmail: Boolean, val password: String, val totp: String?, ) internal sealed interface AutofillSavePlan { data class Add(val entry: VaultEntry) : AutofillSavePlan data class Update(val entry: VaultEntry) : AutofillSavePlan } internal fun autofillSaveDraft(parsed: ParsedStructure): AutofillSaveDraft? { if (!parsed.credentialReleaseAllowed) return null val password = parsed.passwordValue?.trim().orEmpty() if (password.isBlank()) return null val origin = parsed.origin?.trim().orEmpty() if (origin.isBlank()) return null val identity = (parsed.emailValue ?: parsed.usernameValue)?.trim()?.takeIf { it.isNotBlank() } return AutofillSaveDraft( origin = origin, isWebOrigin = parsed.webDomain != null, identity = identity, identityIsEmail = parsed.emailValue?.isNotBlank() == true || identity?.contains("@") == true, password = password, totp = parsed.otpValue?.trim()?.takeIf { it.isNotBlank() }, ) } internal fun planAutofillSave(entries: List, draft: AutofillSaveDraft): AutofillSavePlan { val target = findAutofillUpdateTarget(entries, draft) return if (target == null) { AutofillSavePlan.Add(draft.toEntry()) } else { AutofillSavePlan.Update( target.copy( username = if (!draft.identityIsEmail) draft.identity ?: target.username else target.username, email = if (draft.identityIsEmail) draft.identity ?: target.email else target.email, password = draft.password, totp = draft.totp ?: target.totp, ), ) } } private fun findAutofillUpdateTarget(entries: List, draft: AutofillSaveDraft): VaultEntry? { val candidates = if (draft.isWebOrigin) { AutofillResponseBuilder.matchEntries(entries, draft.origin).hits } else { entries.filter { it.url == draft.origin } }.filter { it.deletedAt == null && it.isLogin() } val identity = draft.identity?.lowercase() if (identity != null) { candidates.firstOrNull { entry -> entry.username?.lowercase() == identity || entry.email?.lowercase() == identity }?.let { return it } } return candidates.singleOrNull() } private fun AutofillSaveDraft.toEntry(): VaultEntry { val title = if (isWebOrigin) getDisplayDomain(origin) else origin return VaultEntry( id = "", type = "login", title = title, username = if (!identityIsEmail) identity else null, email = if (identityIsEmail) identity else null, password = password, url = if (isWebOrigin && !origin.contains("://")) "https://$origin" else origin, totp = totp, createdAt = 0, modifiedAt = 0, ) }