use async_trait::async_trait;
use chrono::{DateTime, Utc};
use sqlx::PgPool;
use tranquil_types::{AtIdentifier, Did, Handle, Jti, PasswordHash, TokenId};
use uuid::Uuid;

use super::col;
use super::{column, legacy_column, opt_column};
use tranquil_db_traits::{
    AccountSearchResult, AccountType, ChannelVerificationStatus, CommsChannel, DbError,
    DidWebOverrides, NotificationPrefs, OAuthTokenWithUser, PasswordResetResult, SsoProviderType,
    StoredBackupCode, StoredPasskey, TotpRecord, TotpRecordState, User2faStatus, UserAuthInfo,
    UserCommsPrefs, UserConfirmSignup, UserDidWebInfo, UserEmailInfo, UserForDeletion,
    UserForDidDoc, UserForDidDocBuild, UserForPasskeyRecovery, UserForPasskeySetup,
    UserForRecovery, UserForVerification, UserIdAndHandle, UserIdAndPasswordHash,
    UserIdHandleEmail, UserInfoForAuth, UserKeyInfo, UserKeyWithId, UserLegacyLoginPref,
    UserLoginCheck, UserLoginFull, UserLoginInfo, UserPasswordInfo, UserRepository,
    UserResendVerification, UserResetCodeInfo, UserRow, UserSessionInfo, UserStatus,
    UserVerificationInfo, UserWithKey, WebauthnChallengeType,
};

pub struct PostgresUserRepository {
    pool: PgPool,
}

impl PostgresUserRepository {
    pub fn new(pool: PgPool) -> Self {
        Self { pool }
    }
}

pub(crate) fn map_sqlx_error(e: sqlx::Error) -> DbError {
    match e {
        sqlx::Error::RowNotFound => DbError::NotFound,
        sqlx::Error::Database(db_err) => {
            let msg = db_err.message().to_string();
            if db_err.is_unique_violation() || db_err.is_foreign_key_violation() {
                DbError::Constraint(msg)
            } else {
                DbError::Query(msg)
            }
        }
        sqlx::Error::PoolTimedOut => DbError::Connection("Pool timed out".into()),
        _ => DbError::Other(e.to_string()),
    }
}

async fn consume_invite_code(
    conn: &mut sqlx::PgConnection,
    code: &str,
    user_id: Uuid,
) -> Result<(), tranquil_db_traits::CreateAccountError> {
    let map_err = |e: sqlx::Error| tranquil_db_traits::CreateAccountError::Database(e.to_string());

    let decremented = sqlx::query!(
        "UPDATE invite_codes SET available_uses = available_uses - 1 WHERE code = $1 AND available_uses > 0 AND COALESCE(disabled, false) = false",
        code
    )
    .execute(&mut *conn)
    .await
    .map_err(map_err)?
    .rows_affected();

    if decremented == 0 {
        return Err(tranquil_db_traits::CreateAccountError::InviteCodeUnavailable);
    }

    sqlx::query!(
        "INSERT INTO invite_code_uses (code, used_by_user) VALUES ($1, $2)",
        code,
        user_id
    )
    .execute(&mut *conn)
    .await
    .map_err(map_err)?;

    Ok(())
}

#[async_trait]
impl UserRepository for PostgresUserRepository {
    async fn get_by_did(&self, did: &Did) -> Result<Option<UserRow>, DbError> {
        let row = sqlx::query!(
            r#"SELECT id, did, handle, email, created_at, deactivated_at, takedown_ref, is_admin, inbound_migration
               FROM users WHERE did = $1"#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        row.map(|r| {
            Ok(UserRow {
                id: r.id,
                did: column(r.did, col::USERS_DID)?,
                handle: column(r.handle, col::USERS_HANDLE)?,
                email: r.email,
                created_at: r.created_at,
                deactivated_at: r.deactivated_at,
                takedown_ref: r.takedown_ref,
                is_admin: r.is_admin,
                inbound_migration: r.inbound_migration,
            })
        })
        .transpose()
    }

    async fn get_by_handle(&self, handle: &Handle) -> Result<Option<UserRow>, DbError> {
        let row = sqlx::query!(
            r#"SELECT id, did, handle, email, created_at, deactivated_at, takedown_ref, is_admin, inbound_migration
               FROM users WHERE handle = $1"#,
            handle.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        row.map(|r| {
            Ok(UserRow {
                id: r.id,
                did: column(r.did, col::USERS_DID)?,
                handle: column(r.handle, col::USERS_HANDLE)?,
                email: r.email,
                created_at: r.created_at,
                deactivated_at: r.deactivated_at,
                takedown_ref: r.takedown_ref,
                is_admin: r.is_admin,
                inbound_migration: r.inbound_migration,
            })
        })
        .transpose()
    }

    async fn get_with_key_by_did(&self, did: &Did) -> Result<Option<UserWithKey>, DbError> {
        let row = sqlx::query!(
            r#"SELECT u.id, u.did, u.handle, u.email, u.deactivated_at, u.takedown_ref, u.is_admin,
                      k.key_bytes, k.encryption_version
               FROM users u
               JOIN user_keys k ON u.id = k.user_id
               WHERE u.did = $1"#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        row.map(|r| {
            Ok(UserWithKey {
                id: r.id,
                did: column(r.did, col::USERS_DID)?,
                handle: column(r.handle, col::USERS_HANDLE)?,
                email: r.email,
                deactivated_at: r.deactivated_at,
                takedown_ref: r.takedown_ref,
                is_admin: r.is_admin,
                key_bytes: r.key_bytes,
                encryption_version: r.encryption_version,
            })
        })
        .transpose()
    }

    async fn get_status_by_did(&self, did: &Did) -> Result<Option<UserStatus>, DbError> {
        let row = sqlx::query!(
            "SELECT deactivated_at, takedown_ref, is_admin FROM users WHERE did = $1",
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(row.map(|r| UserStatus {
            deactivated_at: r.deactivated_at,
            takedown_ref: r.takedown_ref,
            is_admin: r.is_admin,
        }))
    }

    async fn count_users(&self) -> Result<i64, DbError> {
        let row = sqlx::query_scalar!("SELECT COUNT(*) FROM users")
            .fetch_one(&self.pool)
            .await
            .map_err(map_sqlx_error)?;
        Ok(row.unwrap_or(0))
    }

    async fn get_session_access_expiry(
        &self,
        did: &Did,
        access_jti: &Jti,
    ) -> Result<Option<DateTime<Utc>>, DbError> {
        let row = sqlx::query!(
            "SELECT access_expires_at FROM session_tokens WHERE did = $1 AND access_jti = $2",
            did.as_str(),
            access_jti.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(row.map(|r| r.access_expires_at))
    }

    async fn get_oauth_token_with_user(
        &self,
        token_id: &TokenId,
    ) -> Result<Option<OAuthTokenWithUser>, DbError> {
        let row = sqlx::query!(
            r#"SELECT t.did, t.expires_at, u.deactivated_at, u.takedown_ref, u.is_admin,
                      k.key_bytes as "key_bytes?", k.encryption_version as "encryption_version?"
               FROM oauth_token t
               JOIN users u ON t.did = u.did
               LEFT JOIN user_keys k ON u.id = k.user_id
               WHERE t.token_id = $1"#,
            token_id.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        row.map(|r| {
            Ok(OAuthTokenWithUser {
                did: column(r.did, col::OAUTH_TOKEN_DID)?,
                expires_at: r.expires_at,
                deactivated_at: r.deactivated_at,
                takedown_ref: r.takedown_ref,
                is_admin: r.is_admin,
                key_bytes: r.key_bytes,
                encryption_version: r.encryption_version,
            })
        })
        .transpose()
    }

    async fn get_user_info_by_did(&self, did: &Did) -> Result<Option<UserInfoForAuth>, DbError> {
        let row = sqlx::query!(
            r#"SELECT u.deactivated_at, u.takedown_ref, u.is_admin,
                      k.key_bytes as "key_bytes?", k.encryption_version as "encryption_version?"
               FROM users u
               LEFT JOIN user_keys k ON u.id = k.user_id
               WHERE u.did = $1"#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(row.map(|r| UserInfoForAuth {
            deactivated_at: r.deactivated_at,
            takedown_ref: r.takedown_ref,
            is_admin: r.is_admin,
            key_bytes: r.key_bytes,
            encryption_version: r.encryption_version,
        }))
    }

    async fn get_any_admin_user_id(&self) -> Result<Option<Uuid>, DbError> {
        let row = sqlx::query_scalar!("SELECT id FROM users WHERE is_admin = true LIMIT 1")
            .fetch_optional(&self.pool)
            .await
            .map_err(map_sqlx_error)?;
        Ok(row)
    }

    async fn set_invites_disabled(&self, did: &Did, disabled: bool) -> Result<bool, DbError> {
        let result = sqlx::query!(
            "UPDATE users SET invites_disabled = $2 WHERE did = $1",
            did.as_str(),
            disabled
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(result.rows_affected() > 0)
    }

    async fn search_accounts(
        &self,
        cursor_did: Option<&Did>,
        email_filter: Option<&str>,
        handle_filter: Option<&str>,
        limit: i64,
    ) -> Result<Vec<AccountSearchResult>, DbError> {
        let cursor_str = cursor_did.map(|d| d.as_str());
        let email_like = email_filter.map(|e| format!("%{e}%"));
        let handle_like = handle_filter.map(|h| format!("%{h}%"));
        let rows = sqlx::query!(
            r#"SELECT did, handle, email, created_at, email_verified, deactivated_at, invites_disabled
               FROM users
               WHERE ($1::text IS NULL OR did > $1)
                 AND ($2::text IS NULL OR email ILIKE $2)
                 AND ($3::text IS NULL OR handle ILIKE $3)
               ORDER BY did ASC
               LIMIT $4"#,
            cursor_str,
            email_like.as_deref(),
            handle_like.as_deref(),
            limit
        )
        .fetch_all(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(rows
            .into_iter()
            .filter_map(|r| {
                Some(AccountSearchResult {
                    did: legacy_column(r.did, col::USERS_DID)?,
                    handle: legacy_column(r.handle, col::USERS_HANDLE)?,
                    email: r.email,
                    created_at: r.created_at,
                    email_verified: r.email_verified,
                    deactivated_at: r.deactivated_at,
                    invites_disabled: r.invites_disabled,
                })
            })
            .collect())
    }

    async fn get_auth_info_by_did(&self, did: &Did) -> Result<Option<UserAuthInfo>, DbError> {
        let row = sqlx::query!(
            r#"SELECT id, did, password_hash, deactivated_at, takedown_ref,
                      email_verified, discord_verified, telegram_verified, signal_verified
               FROM users
               WHERE did = $1"#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        row.map(|r| {
            Ok(UserAuthInfo {
                id: r.id,
                did: column(r.did, col::USERS_DID)?,
                password_hash: r.password_hash.map(PasswordHash::new),
                deactivated_at: r.deactivated_at,
                takedown_ref: r.takedown_ref,
                channel_verification: ChannelVerificationStatus::from_db_row(
                    r.email_verified,
                    r.discord_verified,
                    r.telegram_verified,
                    r.signal_verified,
                ),
            })
        })
        .transpose()
    }

    async fn get_by_email(&self, email: &str) -> Result<Option<UserForVerification>, DbError> {
        let row = sqlx::query!(
            r#"SELECT id, did, email, email_verified
               FROM users
               WHERE LOWER(email) = $1"#,
            email
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        row.map(|r| {
            Ok(UserForVerification {
                id: r.id,
                did: column(r.did, col::USERS_DID)?,
                email: r.email,
                email_verified: r.email_verified,
            })
        })
        .transpose()
    }

    async fn get_comms_prefs(&self, user_id: Uuid) -> Result<Option<UserCommsPrefs>, DbError> {
        let row = sqlx::query!(
            r#"SELECT email, handle, preferred_comms_channel as "preferred_channel!: CommsChannel", preferred_locale, telegram_chat_id, discord_id, signal_username
               FROM users WHERE id = $1"#,
            user_id
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        row.map(|r| {
            Ok(UserCommsPrefs {
                email: r.email,
                handle: column(r.handle, col::USERS_HANDLE)?,
                preferred_channel: r.preferred_channel,
                preferred_locale: r.preferred_locale,
                telegram_chat_id: r.telegram_chat_id,
                discord_id: r.discord_id,
                signal_username: r.signal_username,
            })
        })
        .transpose()
    }

    async fn get_id_by_did(&self, did: &Did) -> Result<Option<Uuid>, DbError> {
        let id = sqlx::query_scalar!("SELECT id FROM users WHERE did = $1", did.as_str())
            .fetch_optional(&self.pool)
            .await
            .map_err(map_sqlx_error)?;
        Ok(id)
    }

    async fn get_user_key_by_id(&self, user_id: Uuid) -> Result<Option<UserKeyInfo>, DbError> {
        let row = sqlx::query!(
            "SELECT key_bytes, encryption_version FROM user_keys WHERE user_id = $1",
            user_id
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(row.map(|r| UserKeyInfo {
            key_bytes: r.key_bytes,
            encryption_version: r.encryption_version,
        }))
    }

    async fn get_id_and_handle_by_did(
        &self,
        did: &Did,
    ) -> Result<Option<UserIdAndHandle>, DbError> {
        let row = sqlx::query!("SELECT id, handle FROM users WHERE did = $1", did.as_str())
            .fetch_optional(&self.pool)
            .await
            .map_err(map_sqlx_error)?;
        row.map(|r| {
            Ok(UserIdAndHandle {
                id: r.id,
                handle: column(r.handle, col::USERS_HANDLE)?,
            })
        })
        .transpose()
    }

    async fn get_did_web_info_by_handle(
        &self,
        handle: &Handle,
    ) -> Result<Option<UserDidWebInfo>, DbError> {
        let row = sqlx::query!(
            "SELECT id, did, migrated_to_pds FROM users WHERE handle = $1",
            handle.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        row.map(|r| {
            Ok(UserDidWebInfo {
                id: r.id,
                did: column(r.did, col::USERS_DID)?,
                migrated_to_pds: r.migrated_to_pds,
            })
        })
        .transpose()
    }

    async fn get_did_web_overrides(
        &self,
        user_id: Uuid,
    ) -> Result<Option<DidWebOverrides>, DbError> {
        let row = sqlx::query!(
            "SELECT verification_methods, also_known_as FROM did_web_overrides WHERE user_id = $1",
            user_id
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(row.map(|r| DidWebOverrides {
            verification_methods: r.verification_methods,
            also_known_as: r.also_known_as,
        }))
    }

    async fn get_handle_by_did(&self, did: &Did) -> Result<Option<Handle>, DbError> {
        let handle = sqlx::query_scalar!("SELECT handle FROM users WHERE did = $1", did.as_str())
            .fetch_optional(&self.pool)
            .await
            .map_err(map_sqlx_error)?;
        opt_column(handle, col::USERS_HANDLE)
    }

    async fn check_handle_exists(
        &self,
        handle: &Handle,
        exclude_user_id: Uuid,
    ) -> Result<bool, DbError> {
        let exists = sqlx::query_scalar!(
            "SELECT EXISTS(SELECT 1 FROM users WHERE handle = $1 AND id != $2) as \"exists!\"",
            handle.as_str(),
            exclude_user_id
        )
        .fetch_one(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(exists)
    }

    async fn update_handle(&self, user_id: Uuid, handle: &Handle) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET handle = $1 WHERE id = $2",
            handle.as_str(),
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn get_user_with_key_by_did(&self, did: &Did) -> Result<Option<UserKeyWithId>, DbError> {
        let row = sqlx::query!(
            r#"SELECT u.id, uk.key_bytes, uk.encryption_version
               FROM users u
               JOIN user_keys uk ON u.id = uk.user_id
               WHERE u.did = $1"#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(row.map(|r| UserKeyWithId {
            id: r.id,
            key_bytes: r.key_bytes,
            encryption_version: r.encryption_version,
        }))
    }

    async fn is_account_migrated(&self, did: &Did) -> Result<bool, DbError> {
        let row = sqlx::query!(
            r#"SELECT (migrated_to_pds IS NOT NULL AND deactivated_at IS NOT NULL) as "migrated!: bool" FROM users WHERE did = $1"#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(row.map(|r| r.migrated).unwrap_or(false))
    }

    async fn has_verified_comms_channel(&self, did: &Did) -> Result<bool, DbError> {
        let row = sqlx::query!(
            r#"SELECT
                email_verified,
                discord_verified,
                telegram_verified,
                signal_verified
            FROM users
            WHERE did = $1"#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(row
            .map(|r| {
                r.email_verified || r.discord_verified || r.telegram_verified || r.signal_verified
            })
            .unwrap_or(false))
    }

    async fn get_id_by_handle(&self, handle: &Handle) -> Result<Option<Uuid>, DbError> {
        let id = sqlx::query_scalar!("SELECT id FROM users WHERE handle = $1", handle.as_str())
            .fetch_optional(&self.pool)
            .await
            .map_err(map_sqlx_error)?;
        Ok(id)
    }

    async fn get_email_info_by_did(&self, did: &Did) -> Result<Option<UserEmailInfo>, DbError> {
        let row = sqlx::query!(
            "SELECT id, handle, email, email_verified FROM users WHERE did = $1",
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        row.map(|r| {
            Ok(UserEmailInfo {
                id: r.id,
                handle: column(r.handle, col::USERS_HANDLE)?,
                email: r.email,
                email_verified: r.email_verified,
            })
        })
        .transpose()
    }

    async fn check_email_exists(
        &self,
        email: &str,
        exclude_user_id: Uuid,
    ) -> Result<bool, DbError> {
        let row = sqlx::query!(
            "SELECT 1 as one FROM users WHERE LOWER(email) = $1 AND id != $2",
            email.to_lowercase(),
            exclude_user_id
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(row.is_some())
    }

    async fn update_email(&self, user_id: Uuid, email: &str) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET email = $1, email_verified = FALSE, updated_at = NOW() WHERE id = $2",
            email,
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn set_email_verified(&self, user_id: Uuid, verified: bool) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET email_verified = $1, updated_at = NOW() WHERE id = $2",
            verified,
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn check_email_verified_by_identifier(
        &self,
        identifier: &AtIdentifier,
    ) -> Result<Option<bool>, DbError> {
        let row = sqlx::query_scalar!(
            "SELECT email_verified FROM users WHERE did = $1 OR email = $1 OR handle = $1",
            identifier.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(row)
    }

    async fn check_channel_verified_by_did(
        &self,
        did: &Did,
        channel: CommsChannel,
    ) -> Result<Option<bool>, DbError> {
        let row = sqlx::query!(
            r#"SELECT
                email_verified,
                discord_verified,
                telegram_verified,
                signal_verified
            FROM users
            WHERE did = $1"#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(row.map(|r| match channel {
            CommsChannel::Email => r.email_verified,
            CommsChannel::Discord => r.discord_verified,
            CommsChannel::Telegram => r.telegram_verified,
            CommsChannel::Signal => r.signal_verified,
        }))
    }

    async fn admin_update_email(&self, did: &Did, email: &str) -> Result<u64, DbError> {
        let result = sqlx::query!(
            "UPDATE users SET email = $1 WHERE did = $2",
            email,
            did.as_str()
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(result.rows_affected())
    }

    async fn admin_update_handle(&self, did: &Did, handle: &Handle) -> Result<u64, DbError> {
        let result = sqlx::query!(
            "UPDATE users SET handle = $1 WHERE did = $2",
            handle.as_str(),
            did.as_str()
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(result.rows_affected())
    }

    async fn admin_update_password(
        &self,
        did: &Did,
        password_hash: &PasswordHash,
    ) -> Result<u64, DbError> {
        let result = sqlx::query!(
            "UPDATE users SET password_hash = $1 WHERE did = $2",
            password_hash.as_str(),
            did.as_str()
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(result.rows_affected())
    }

    async fn set_admin_status(&self, did: &Did, is_admin: bool) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET is_admin = $1 WHERE did = $2",
            is_admin,
            did.as_str()
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn get_notification_prefs(
        &self,
        did: &Did,
    ) -> Result<Option<NotificationPrefs>, DbError> {
        let row = sqlx::query!(
            r#"SELECT
                email,
                preferred_comms_channel as "preferred_channel!: CommsChannel",
                discord_id,
                discord_username,
                discord_verified,
                telegram_username,
                telegram_verified,
                telegram_chat_id,
                signal_username,
                signal_verified
            FROM users WHERE did = $1"#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(row.map(|r| NotificationPrefs {
            email: r.email.unwrap_or_default(),
            preferred_channel: r.preferred_channel,
            discord_id: r.discord_id,
            discord_username: r.discord_username,
            discord_verified: r.discord_verified,
            telegram_username: r.telegram_username,
            telegram_verified: r.telegram_verified,
            telegram_chat_id: r.telegram_chat_id,
            signal_username: r.signal_username,
            signal_verified: r.signal_verified,
        }))
    }

    async fn get_id_handle_email_by_did(
        &self,
        did: &Did,
    ) -> Result<Option<UserIdHandleEmail>, DbError> {
        let row = sqlx::query!(
            "SELECT id, handle, email FROM users WHERE did = $1",
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        row.map(|r| {
            Ok(UserIdHandleEmail {
                id: r.id,
                handle: column(r.handle, col::USERS_HANDLE)?,
                email: r.email,
            })
        })
        .transpose()
    }

    async fn update_preferred_comms_channel(
        &self,
        did: &Did,
        channel: CommsChannel,
    ) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET preferred_comms_channel = $1, updated_at = NOW() WHERE did = $2",
            channel as CommsChannel,
            did.as_str()
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn clear_discord(&self, user_id: Uuid) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET discord_id = NULL, discord_username = NULL, discord_verified = FALSE, updated_at = NOW() WHERE id = $1",
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn clear_telegram(&self, user_id: Uuid) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET telegram_username = NULL, telegram_verified = FALSE, telegram_chat_id = NULL, updated_at = NOW() WHERE id = $1",
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn clear_signal(&self, user_id: Uuid) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET signal_username = NULL, signal_verified = FALSE, updated_at = NOW() WHERE id = $1",
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn get_verification_info(
        &self,
        did: &Did,
    ) -> Result<Option<UserVerificationInfo>, DbError> {
        let row = sqlx::query!(
            r#"SELECT id, handle, email, email_verified, discord_verified, telegram_verified, signal_verified
               FROM users WHERE did = $1"#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        row.map(|r| {
            Ok(UserVerificationInfo {
                id: r.id,
                handle: column(r.handle, col::USERS_HANDLE)?,
                email: r.email,
                channel_verification: ChannelVerificationStatus::from_db_row(
                    r.email_verified,
                    r.discord_verified,
                    r.telegram_verified,
                    r.signal_verified,
                ),
            })
        })
        .transpose()
    }

    async fn verify_email_channel(&self, user_id: Uuid, email: &str) -> Result<bool, DbError> {
        sqlx::query!(
            "UPDATE users SET email = $1, email_verified = TRUE, updated_at = NOW() WHERE id = $2",
            email,
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(true)
    }

    async fn verify_discord_channel(&self, user_id: Uuid, discord_id: &str) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET discord_id = $1, discord_verified = TRUE, updated_at = NOW() WHERE id = $2",
            discord_id,
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn verify_telegram_channel(
        &self,
        user_id: Uuid,
        telegram_username: &str,
    ) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET telegram_username = $1, telegram_verified = TRUE, updated_at = NOW() WHERE id = $2",
            telegram_username,
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn verify_signal_channel(
        &self,
        user_id: Uuid,
        signal_username: &str,
    ) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET signal_username = $1, signal_verified = TRUE, updated_at = NOW() WHERE id = $2",
            signal_username,
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn set_email_verified_flag(&self, user_id: Uuid) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET email_verified = TRUE WHERE id = $1",
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn set_discord_verified_flag(&self, user_id: Uuid) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET discord_verified = TRUE WHERE id = $1",
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn set_telegram_verified_flag(&self, user_id: Uuid) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET telegram_verified = TRUE WHERE id = $1",
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn set_signal_verified_flag(&self, user_id: Uuid) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET signal_verified = TRUE WHERE id = $1",
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn has_totp_enabled(&self, did: &Did) -> Result<bool, DbError> {
        let row = sqlx::query_scalar!(
            "SELECT verified FROM user_totp WHERE did = $1",
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(matches!(row, Some(true)))
    }

    async fn has_passkeys(&self, did: &Did) -> Result<bool, DbError> {
        let count = sqlx::query_scalar!(
            "SELECT COUNT(*) as count FROM passkeys WHERE did = $1",
            did.as_str()
        )
        .fetch_one(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(count.unwrap_or(0) > 0)
    }

    async fn get_password_hash_by_did(&self, did: &Did) -> Result<Option<PasswordHash>, DbError> {
        let row = sqlx::query_scalar!(
            "SELECT password_hash FROM users WHERE did = $1",
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(row.flatten().map(PasswordHash::new))
    }

    async fn get_passkeys_for_user(&self, did: &Did) -> Result<Vec<StoredPasskey>, DbError> {
        let rows = sqlx::query!(
            r#"SELECT id, did, credential_id, public_key, sign_count, created_at, last_used,
                      friendly_name, aaguid, transports
               FROM passkeys WHERE did = $1 ORDER BY created_at DESC"#,
            did.as_str()
        )
        .fetch_all(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        rows.into_iter()
            .map(|r| {
                Ok(StoredPasskey {
                    id: r.id,
                    did: column(r.did, col::PASSKEYS_DID)?,
                    credential_id: r.credential_id,
                    public_key: r.public_key,
                    sign_count: r.sign_count,
                    created_at: r.created_at,
                    last_used: r.last_used,
                    friendly_name: r.friendly_name,
                    aaguid: r.aaguid,
                    transports: r.transports,
                })
            })
            .collect()
    }

    async fn get_passkey_by_credential_id(
        &self,
        credential_id: &[u8],
    ) -> Result<Option<StoredPasskey>, DbError> {
        let row = sqlx::query!(
            r#"SELECT id, did, credential_id, public_key, sign_count, created_at, last_used,
                      friendly_name, aaguid, transports
               FROM passkeys WHERE credential_id = $1"#,
            credential_id
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        row.map(|r| {
            Ok(StoredPasskey {
                id: r.id,
                did: column(r.did, col::PASSKEYS_DID)?,
                credential_id: r.credential_id,
                public_key: r.public_key,
                sign_count: r.sign_count,
                created_at: r.created_at,
                last_used: r.last_used,
                friendly_name: r.friendly_name,
                aaguid: r.aaguid,
                transports: r.transports,
            })
        })
        .transpose()
    }

    async fn save_passkey(
        &self,
        did: &Did,
        credential_id: &[u8],
        public_key: &[u8],
        friendly_name: Option<&str>,
    ) -> Result<Uuid, DbError> {
        let id = Uuid::new_v4();
        let aaguid: Option<Vec<u8>> = None;
        sqlx::query!(
            r#"INSERT INTO passkeys (id, did, credential_id, public_key, sign_count, friendly_name, aaguid)
               VALUES ($1, $2, $3, $4, 0, $5, $6)"#,
            id,
            did.as_str(),
            credential_id,
            public_key,
            friendly_name,
            aaguid,
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(id)
    }

    async fn update_passkey_counter(
        &self,
        credential_id: &[u8],
        new_counter: i32,
    ) -> Result<bool, DbError> {
        let stored = self.get_passkey_by_credential_id(credential_id).await?;
        let Some(stored) = stored else {
            return Err(DbError::NotFound);
        };

        if new_counter > 0 && new_counter <= stored.sign_count {
            return Ok(false);
        }

        sqlx::query!(
            "UPDATE passkeys SET sign_count = $1, last_used = NOW() WHERE credential_id = $2",
            new_counter,
            credential_id,
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(true)
    }

    async fn delete_passkey(&self, id: Uuid, did: &Did) -> Result<bool, DbError> {
        let result = sqlx::query!(
            "DELETE FROM passkeys WHERE id = $1 AND did = $2",
            id,
            did.as_str()
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(result.rows_affected() > 0)
    }

    async fn update_passkey_name(&self, id: Uuid, did: &Did, name: &str) -> Result<bool, DbError> {
        let result = sqlx::query!(
            "UPDATE passkeys SET friendly_name = $1 WHERE id = $2 AND did = $3",
            name,
            id,
            did.as_str()
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(result.rows_affected() > 0)
    }

    async fn save_webauthn_challenge(
        &self,
        did: &Did,
        challenge_type: WebauthnChallengeType,
        state_json: &str,
    ) -> Result<Uuid, DbError> {
        let id = Uuid::new_v4();
        let challenge = id.as_bytes().to_vec();
        let expires_at = chrono::Utc::now() + chrono::Duration::minutes(5);
        sqlx::query!(
            r#"INSERT INTO webauthn_challenges (id, did, challenge, challenge_type, state_json, expires_at)
               VALUES ($1, $2, $3, $4, $5, $6)"#,
            id,
            did.as_str(),
            challenge,
            challenge_type.as_str(),
            state_json,
            expires_at,
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(id)
    }

    async fn load_webauthn_challenge(
        &self,
        did: &Did,
        challenge_type: WebauthnChallengeType,
    ) -> Result<Option<String>, DbError> {
        let row = sqlx::query_scalar!(
            r#"SELECT state_json FROM webauthn_challenges
               WHERE did = $1 AND challenge_type = $2 AND expires_at > NOW()
               ORDER BY created_at DESC LIMIT 1"#,
            did.as_str(),
            challenge_type.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(row)
    }

    async fn delete_webauthn_challenge(
        &self,
        did: &Did,
        challenge_type: WebauthnChallengeType,
    ) -> Result<(), DbError> {
        sqlx::query!(
            "DELETE FROM webauthn_challenges WHERE did = $1 AND challenge_type = $2",
            did.as_str(),
            challenge_type.as_str()
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(())
    }

    async fn save_discoverable_challenge(
        &self,
        request_key: &str,
        state_json: &str,
    ) -> Result<Uuid, DbError> {
        let id = Uuid::new_v4();
        let challenge = id.as_bytes().to_vec();
        let expires_at = chrono::Utc::now() + chrono::Duration::minutes(5);
        sqlx::query!(
            r#"INSERT INTO webauthn_challenges (id, did, challenge, challenge_type, state_json, expires_at)
               VALUES ($1, $2, $3, 'discoverable', $4, $5)"#,
            id,
            request_key,
            challenge,
            state_json,
            expires_at,
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(id)
    }

    async fn load_discoverable_challenge(
        &self,
        request_key: &str,
    ) -> Result<Option<String>, DbError> {
        let row = sqlx::query_scalar!(
            r#"SELECT state_json FROM webauthn_challenges
               WHERE did = $1 AND challenge_type = 'discoverable' AND expires_at > NOW()
               ORDER BY created_at DESC LIMIT 1"#,
            request_key,
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(row)
    }

    async fn delete_discoverable_challenge(&self, request_key: &str) -> Result<(), DbError> {
        sqlx::query!(
            "DELETE FROM webauthn_challenges WHERE did = $1 AND challenge_type = 'discoverable'",
            request_key,
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(())
    }

    async fn get_totp_record(&self, did: &Did) -> Result<Option<TotpRecord>, DbError> {
        let row = sqlx::query!(
            "SELECT secret_encrypted, encryption_version, verified FROM user_totp WHERE did = $1",
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(row.map(|r| TotpRecord {
            secret_encrypted: r.secret_encrypted,
            encryption_version: r.encryption_version,
            verified: r.verified,
        }))
    }

    async fn get_totp_record_state(&self, did: &Did) -> Result<Option<TotpRecordState>, DbError> {
        self.get_totp_record(did)
            .await
            .map(|opt| opt.map(TotpRecordState::from))
    }

    async fn upsert_totp_secret(
        &self,
        did: &Did,
        secret_encrypted: &[u8],
        encryption_version: i32,
    ) -> Result<(), DbError> {
        sqlx::query!(
            r#"INSERT INTO user_totp (did, secret_encrypted, encryption_version, verified, created_at)
               VALUES ($1, $2, $3, false, NOW())
               ON CONFLICT (did) DO UPDATE SET
                   secret_encrypted = $2,
                   encryption_version = $3,
                   verified = false,
                   created_at = NOW(),
                   last_used = NULL"#,
            did.as_str(),
            secret_encrypted,
            encryption_version
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(())
    }

    async fn set_totp_verified(&self, did: &Did) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE user_totp SET verified = true, last_used = NOW() WHERE did = $1",
            did.as_str()
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(())
    }

    async fn update_totp_last_used(&self, did: &Did) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE user_totp SET last_used = NOW() WHERE did = $1",
            did.as_str()
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(())
    }

    async fn delete_totp(&self, did: &Did) -> Result<(), DbError> {
        sqlx::query!("DELETE FROM user_totp WHERE did = $1", did.as_str())
            .execute(&self.pool)
            .await
            .map_err(map_sqlx_error)?;

        Ok(())
    }

    async fn get_unused_backup_codes(&self, did: &Did) -> Result<Vec<StoredBackupCode>, DbError> {
        let rows = sqlx::query!(
            "SELECT id, code_hash FROM backup_codes WHERE did = $1 AND used_at IS NULL",
            did.as_str()
        )
        .fetch_all(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(rows
            .into_iter()
            .map(|r| StoredBackupCode {
                id: r.id,
                code_hash: r.code_hash,
            })
            .collect())
    }

    async fn mark_backup_code_used(&self, code_id: Uuid) -> Result<bool, DbError> {
        let result = sqlx::query!(
            "UPDATE backup_codes SET used_at = NOW() WHERE id = $1",
            code_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(result.rows_affected() > 0)
    }

    async fn count_unused_backup_codes(&self, did: &Did) -> Result<i64, DbError> {
        let row = sqlx::query!(
            "SELECT COUNT(*) as count FROM backup_codes WHERE did = $1 AND used_at IS NULL",
            did.as_str()
        )
        .fetch_one(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(row.count.unwrap_or(0))
    }

    async fn delete_backup_codes(&self, did: &Did) -> Result<u64, DbError> {
        let result = sqlx::query!("DELETE FROM backup_codes WHERE did = $1", did.as_str())
            .execute(&self.pool)
            .await
            .map_err(map_sqlx_error)?;

        Ok(result.rows_affected())
    }

    async fn insert_backup_codes(&self, did: &Did, code_hashes: &[String]) -> Result<(), DbError> {
        sqlx::query!(
            r#"
            INSERT INTO backup_codes (did, code_hash, created_at)
            SELECT $1, hash, NOW() FROM UNNEST($2::text[]) AS t(hash)
            "#,
            did.as_str(),
            code_hashes
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(())
    }

    async fn enable_totp_with_backup_codes(
        &self,
        did: &Did,
        code_hashes: &[String],
    ) -> Result<(), DbError> {
        let mut tx = self.pool.begin().await.map_err(map_sqlx_error)?;

        sqlx::query!(
            "UPDATE user_totp SET verified = true, last_used = NOW() WHERE did = $1",
            did.as_str()
        )
        .execute(&mut *tx)
        .await
        .map_err(map_sqlx_error)?;

        sqlx::query!("DELETE FROM backup_codes WHERE did = $1", did.as_str())
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        sqlx::query!(
            r#"
            INSERT INTO backup_codes (did, code_hash, created_at)
            SELECT $1, hash, NOW() FROM UNNEST($2::text[]) AS t(hash)
            "#,
            did.as_str(),
            code_hashes
        )
        .execute(&mut *tx)
        .await
        .map_err(map_sqlx_error)?;

        tx.commit().await.map_err(map_sqlx_error)?;

        Ok(())
    }

    async fn delete_totp_and_backup_codes(&self, did: &Did) -> Result<(), DbError> {
        let mut tx = self.pool.begin().await.map_err(map_sqlx_error)?;

        sqlx::query!("DELETE FROM user_totp WHERE did = $1", did.as_str())
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        sqlx::query!("DELETE FROM backup_codes WHERE did = $1", did.as_str())
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        tx.commit().await.map_err(map_sqlx_error)?;

        Ok(())
    }

    async fn replace_backup_codes(&self, did: &Did, code_hashes: &[String]) -> Result<(), DbError> {
        let mut tx = self.pool.begin().await.map_err(map_sqlx_error)?;

        sqlx::query!("DELETE FROM backup_codes WHERE did = $1", did.as_str())
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        sqlx::query!(
            r#"
            INSERT INTO backup_codes (did, code_hash, created_at)
            SELECT $1, hash, NOW() FROM UNNEST($2::text[]) AS t(hash)
            "#,
            did.as_str(),
            code_hashes
        )
        .execute(&mut *tx)
        .await
        .map_err(map_sqlx_error)?;

        tx.commit().await.map_err(map_sqlx_error)?;

        Ok(())
    }

    async fn get_login_check_by_identifier(
        &self,
        identifier: &AtIdentifier,
    ) -> Result<Option<UserLoginCheck>, DbError> {
        sqlx::query!(
            "SELECT did, password_hash FROM users WHERE handle = $1 OR did = $1",
            identifier.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?
        .map(|r| {
            Ok(UserLoginCheck {
                did: column(r.did, col::USERS_DID)?,
                password_hash: r.password_hash.map(PasswordHash::new),
            })
        })
        .transpose()
    }

    async fn get_login_info_by_identifier(
        &self,
        identifier: &AtIdentifier,
    ) -> Result<Option<UserLoginInfo>, DbError> {
        sqlx::query!(
            r#"
            SELECT id, did, email, password_hash, password_required, two_factor_enabled,
                   preferred_comms_channel as "preferred_comms_channel!: CommsChannel",
                   deactivated_at, takedown_ref,
                   email_verified, discord_verified, telegram_verified, signal_verified,
                   account_type as "account_type!: AccountType"
            FROM users
            WHERE handle = $1 OR did = $1
            "#,
            identifier.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?
        .map(|row| {
            Ok(UserLoginInfo {
                id: row.id,
                did: column(row.did, col::USERS_DID)?,
                email: row.email,
                password_hash: row.password_hash.map(PasswordHash::new),
                password_required: row.password_required,
                two_factor_enabled: row.two_factor_enabled,
                preferred_comms_channel: row.preferred_comms_channel,
                deactivated_at: row.deactivated_at,
                takedown_ref: row.takedown_ref,
                channel_verification: ChannelVerificationStatus::from_db_row(
                    row.email_verified,
                    row.discord_verified,
                    row.telegram_verified,
                    row.signal_verified,
                ),
                account_type: row.account_type,
            })
        })
        .transpose()
    }

    async fn get_2fa_status_by_did(&self, did: &Did) -> Result<Option<User2faStatus>, DbError> {
        sqlx::query!(
            r#"
            SELECT id, two_factor_enabled,
                   preferred_comms_channel as "preferred_comms_channel!: CommsChannel",
                   email_verified, discord_verified, telegram_verified, signal_verified
            FROM users
            WHERE did = $1
            "#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)
        .map(|opt| {
            opt.map(|row| User2faStatus {
                id: row.id,
                two_factor_enabled: row.two_factor_enabled,
                preferred_comms_channel: row.preferred_comms_channel,
                channel_verification: ChannelVerificationStatus::from_db_row(
                    row.email_verified,
                    row.discord_verified,
                    row.telegram_verified,
                    row.signal_verified,
                ),
            })
        })
    }

    async fn get_session_info_by_did(&self, did: &Did) -> Result<Option<UserSessionInfo>, DbError> {
        sqlx::query!(
            r#"
            SELECT u.handle, u.email, u.email_verified, u.is_admin, u.deactivated_at, u.takedown_ref,
                   u.preferred_locale,
                   u.preferred_comms_channel as "preferred_comms_channel!: CommsChannel",
                   u.discord_verified, u.telegram_verified, u.signal_verified,
                   u.migrated_to_pds, u.migrated_at,
                   (SELECT verified FROM user_totp WHERE did = u.did) as totp_enabled,
                   COALESCE((SELECT (value_json)::boolean FROM account_preferences WHERE user_id = u.id AND name = 'email_auth_factor' ORDER BY created_at DESC LIMIT 1), false) as "email_2fa_enabled!"
            FROM users u
            WHERE u.did = $1
            "#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?
        .map(|row| {
            Ok(UserSessionInfo {
                handle: column(row.handle, col::USERS_HANDLE)?,
                email: row.email,
                is_admin: row.is_admin,
                deactivated_at: row.deactivated_at,
                takedown_ref: row.takedown_ref,
                preferred_locale: row.preferred_locale,
                preferred_comms_channel: row.preferred_comms_channel,
                channel_verification: ChannelVerificationStatus::from_db_row(
                    row.email_verified,
                    row.discord_verified,
                    row.telegram_verified,
                    row.signal_verified,
                ),
                migrated_to_pds: row.migrated_to_pds,
                migrated_at: row.migrated_at,
                totp_enabled: row.totp_enabled.unwrap_or(false),
                email_2fa_enabled: row.email_2fa_enabled,
            })
        })
        .transpose()
    }

    async fn get_legacy_login_pref(
        &self,
        did: &Did,
    ) -> Result<Option<UserLegacyLoginPref>, DbError> {
        sqlx::query!(
            r#"
            SELECT u.allow_legacy_login,
                   (EXISTS(SELECT 1 FROM user_totp t WHERE t.did = u.did AND t.verified = TRUE) OR
                    EXISTS(SELECT 1 FROM passkeys p WHERE p.did = u.did)) as "has_mfa!"
            FROM users u
            WHERE u.did = $1
            "#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)
        .map(|opt| {
            opt.map(|row| UserLegacyLoginPref {
                allow_legacy_login: row.allow_legacy_login,
                has_mfa: row.has_mfa,
            })
        })
    }

    async fn update_legacy_login(&self, did: &Did, allow: bool) -> Result<bool, DbError> {
        let result = sqlx::query!(
            "UPDATE users SET allow_legacy_login = $1 WHERE did = $2 RETURNING did",
            allow,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(result.is_some())
    }

    async fn update_locale(&self, did: &Did, locale: &str) -> Result<bool, DbError> {
        let result = sqlx::query!(
            "UPDATE users SET preferred_locale = $1 WHERE did = $2 RETURNING did",
            locale,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(result.is_some())
    }

    async fn get_login_full_by_identifier(
        &self,
        identifier: &AtIdentifier,
    ) -> Result<Option<UserLoginFull>, DbError> {
        sqlx::query!(
            r#"SELECT
                u.id, u.did, u.handle, u.password_hash, u.email, u.deactivated_at, u.takedown_ref,
                u.email_verified, u.discord_verified, u.telegram_verified, u.signal_verified,
                u.allow_legacy_login, u.migrated_to_pds,
                u.preferred_comms_channel as "preferred_comms_channel: CommsChannel",
                k.key_bytes, k.encryption_version,
                (SELECT verified FROM user_totp WHERE did = u.did) as totp_enabled,
                COALESCE((SELECT (value_json)::boolean FROM account_preferences WHERE user_id = u.id AND name = 'email_auth_factor' ORDER BY created_at DESC LIMIT 1), false) as "email_2fa_enabled!"
            FROM users u
            JOIN user_keys k ON u.id = k.user_id
            WHERE u.handle = $1 OR u.did = $1"#,
            identifier.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?
        .map(|row| {
            Ok(UserLoginFull {
                id: row.id,
                did: column(row.did, col::USERS_DID)?,
                handle: column(row.handle, col::USERS_HANDLE)?,
                password_hash: row.password_hash.map(PasswordHash::new),
                email: row.email,
                deactivated_at: row.deactivated_at,
                takedown_ref: row.takedown_ref,
                channel_verification: ChannelVerificationStatus::from_db_row(
                    row.email_verified,
                    row.discord_verified,
                    row.telegram_verified,
                    row.signal_verified,
                ),
                allow_legacy_login: row.allow_legacy_login,
                migrated_to_pds: row.migrated_to_pds,
                preferred_comms_channel: row.preferred_comms_channel,
                key_bytes: row.key_bytes,
                encryption_version: row.encryption_version,
                totp_enabled: row.totp_enabled.unwrap_or(false),
                email_2fa_enabled: row.email_2fa_enabled,
            })
        })
        .transpose()
    }

    async fn get_confirm_signup_by_did(
        &self,
        did: &Did,
    ) -> Result<Option<UserConfirmSignup>, DbError> {
        sqlx::query!(
            r#"SELECT
                u.id, u.did, u.handle, u.email,
                u.preferred_comms_channel as "channel: CommsChannel",
                u.discord_username, u.telegram_username, u.signal_username,
                k.key_bytes, k.encryption_version
            FROM users u
            JOIN user_keys k ON u.id = k.user_id
            WHERE u.did = $1"#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?
        .map(|row| {
            Ok(UserConfirmSignup {
                id: row.id,
                did: column(row.did, col::USERS_DID)?,
                handle: column(row.handle, col::USERS_HANDLE)?,
                email: row.email,
                channel: row.channel,
                discord_username: row.discord_username,
                telegram_username: row.telegram_username,
                signal_username: row.signal_username,
                key_bytes: row.key_bytes,
                encryption_version: row.encryption_version,
            })
        })
        .transpose()
    }

    async fn get_resend_verification_by_did(
        &self,
        did: &Did,
    ) -> Result<Option<UserResendVerification>, DbError> {
        sqlx::query!(
            r#"SELECT
                id, handle, email,
                preferred_comms_channel as "channel: CommsChannel",
                discord_username, telegram_username, signal_username,
                email_verified, discord_verified, telegram_verified, signal_verified
            FROM users
            WHERE did = $1"#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?
        .map(|row| {
            Ok(UserResendVerification {
                id: row.id,
                handle: column(row.handle, col::USERS_HANDLE)?,
                email: row.email,
                channel: row.channel,
                discord_username: row.discord_username,
                telegram_username: row.telegram_username,
                signal_username: row.signal_username,
                channel_verification: ChannelVerificationStatus::from_db_row(
                    row.email_verified,
                    row.discord_verified,
                    row.telegram_verified,
                    row.signal_verified,
                ),
            })
        })
        .transpose()
    }

    async fn set_channel_verified(&self, did: &Did, channel: CommsChannel) -> Result<(), DbError> {
        let column = match channel {
            CommsChannel::Email => "email_verified",
            CommsChannel::Discord => "discord_verified",
            CommsChannel::Telegram => "telegram_verified",
            CommsChannel::Signal => "signal_verified",
        };
        let query = format!("UPDATE users SET {} = TRUE WHERE did = $1", column);
        sqlx::query(&query)
            .bind(did.as_str())
            .execute(&self.pool)
            .await
            .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn get_id_by_email_or_handle(
        &self,
        email: &str,
        handle: &Handle,
    ) -> Result<Option<Uuid>, DbError> {
        sqlx::query_scalar!(
            "SELECT id FROM users WHERE LOWER(email) = $1 OR handle = $2",
            email,
            handle.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)
    }

    async fn count_accounts_by_email(&self, email: &str) -> Result<i64, DbError> {
        sqlx::query_scalar!(
            "SELECT COUNT(*) FROM users WHERE LOWER(email) = LOWER($1) AND deactivated_at IS NULL",
            email
        )
        .fetch_one(&self.pool)
        .await
        .map(|c| c.unwrap_or(0))
        .map_err(map_sqlx_error)
    }

    async fn get_handles_by_email(&self, email: &str) -> Result<Vec<Handle>, DbError> {
        let handles = sqlx::query_scalar!(
            "SELECT handle FROM users WHERE LOWER(email) = LOWER($1) AND deactivated_at IS NULL ORDER BY created_at DESC",
            email
        )
        .fetch_all(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(handles
            .into_iter()
            .filter_map(|h| legacy_column(h, col::USERS_HANDLE))
            .collect())
    }

    async fn set_password_reset_code(
        &self,
        user_id: Uuid,
        code: &str,
        expires_at: DateTime<Utc>,
    ) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET password_reset_code = $1, password_reset_code_expires_at = $2 WHERE id = $3",
            code,
            expires_at,
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn get_user_by_reset_code(
        &self,
        code: &str,
    ) -> Result<Option<UserResetCodeInfo>, DbError> {
        sqlx::query!(
            "SELECT id, did, preferred_comms_channel as \"preferred_comms_channel: CommsChannel\", password_reset_code_expires_at FROM users WHERE password_reset_code = $1",
            code
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?
        .map(|row| {
            Ok(UserResetCodeInfo {
                id: row.id,
                did: column(row.did, col::USERS_DID)?,
                preferred_comms_channel: row.preferred_comms_channel,
                expires_at: row.password_reset_code_expires_at,
            })
        })
        .transpose()
    }

    async fn clear_password_reset_code(&self, user_id: Uuid) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET password_reset_code = NULL, password_reset_code_expires_at = NULL WHERE id = $1",
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn get_id_and_password_hash_by_did(
        &self,
        did: &Did,
    ) -> Result<Option<UserIdAndPasswordHash>, DbError> {
        sqlx::query!(
            "SELECT id, password_hash FROM users WHERE did = $1",
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)
        .map(|opt| {
            opt.and_then(|row| {
                row.password_hash.map(|hash| UserIdAndPasswordHash {
                    id: row.id,
                    password_hash: PasswordHash::new(hash),
                })
            })
        })
    }

    async fn update_password_hash(
        &self,
        user_id: Uuid,
        password_hash: &PasswordHash,
    ) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET password_hash = $1 WHERE id = $2",
            password_hash.as_str(),
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn reset_password_with_sessions(
        &self,
        user_id: Uuid,
        password_hash: &PasswordHash,
    ) -> Result<PasswordResetResult, DbError> {
        let mut tx = self.pool.begin().await.map_err(map_sqlx_error)?;

        sqlx::query!(
            "UPDATE users SET password_hash = $1, password_reset_code = NULL, password_reset_code_expires_at = NULL, password_required = TRUE WHERE id = $2",
            password_hash.as_str(),
            user_id
        )
        .execute(&mut *tx)
        .await
        .map_err(map_sqlx_error)?;

        let user_did = sqlx::query_scalar!("SELECT did FROM users WHERE id = $1", user_id)
            .fetch_one(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        let session_jtis: Vec<Jti> = sqlx::query_scalar!(
            "SELECT access_jti FROM session_tokens WHERE did = $1",
            user_did
        )
        .fetch_all(&mut *tx)
        .await
        .map_err(map_sqlx_error)?
        .into_iter()
        .map(Jti::from)
        .collect();

        sqlx::query!("DELETE FROM session_tokens WHERE did = $1", user_did)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        let did = column(user_did, col::USERS_DID)?;

        tx.commit().await.map_err(map_sqlx_error)?;

        Ok(PasswordResetResult { did, session_jtis })
    }

    async fn activate_account(&self, did: &Did) -> Result<bool, DbError> {
        let result = sqlx::query!(
            "UPDATE users SET deactivated_at = NULL, inbound_migration = FALSE WHERE did = $1",
            did.as_str()
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(result.rows_affected() > 0)
    }

    async fn deactivate_account(
        &self,
        did: &Did,
        delete_after: Option<DateTime<Utc>>,
    ) -> Result<bool, DbError> {
        let result = sqlx::query!(
            "UPDATE users SET deactivated_at = NOW(), delete_after = $2 WHERE did = $1",
            did.as_str(),
            delete_after
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(result.rows_affected() > 0)
    }

    async fn has_password_by_did(&self, did: &Did) -> Result<Option<bool>, DbError> {
        sqlx::query_scalar!(
            "SELECT password_hash IS NOT NULL as has_password FROM users WHERE did = $1",
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)
        .map(|opt| opt.flatten())
    }

    async fn get_password_info_by_did(
        &self,
        did: &Did,
    ) -> Result<Option<UserPasswordInfo>, DbError> {
        sqlx::query!(
            "SELECT id, password_hash FROM users WHERE did = $1",
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)
        .map(|opt| {
            opt.map(|row| UserPasswordInfo {
                id: row.id,
                password_hash: row.password_hash.map(PasswordHash::new),
            })
        })
    }

    async fn remove_user_password(&self, user_id: Uuid) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET password_hash = NULL, password_required = FALSE WHERE id = $1",
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn set_new_user_password(
        &self,
        user_id: Uuid,
        password_hash: &PasswordHash,
    ) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET password_hash = $1, password_required = TRUE WHERE id = $2",
            password_hash.as_str(),
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn is_account_active_by_did(&self, did: &Did) -> Result<Option<bool>, DbError> {
        sqlx::query_scalar!(
            "SELECT deactivated_at IS NULL as is_active FROM users WHERE did = $1",
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)
        .map(|opt| opt.flatten())
    }

    async fn get_user_for_deletion(&self, did: &Did) -> Result<Option<UserForDeletion>, DbError> {
        sqlx::query!(
            "SELECT id, password_hash, handle FROM users WHERE did = $1",
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?
        .map(|row| {
            Ok(UserForDeletion {
                id: row.id,
                password_hash: row.password_hash.map(PasswordHash::new),
                handle: column(row.handle, col::USERS_HANDLE)?,
            })
        })
        .transpose()
    }

    async fn get_user_key_by_did(&self, did: &Did) -> Result<Option<UserKeyInfo>, DbError> {
        sqlx::query!(
            r#"SELECT uk.key_bytes, uk.encryption_version
               FROM user_keys uk
               JOIN users u ON uk.user_id = u.id
               WHERE u.did = $1"#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)
        .map(|opt| {
            opt.map(|row| UserKeyInfo {
                key_bytes: row.key_bytes,
                encryption_version: row.encryption_version,
            })
        })
    }

    async fn delete_account_complete(&self, user_id: Uuid, did: &Did) -> Result<(), DbError> {
        let mut tx = self.pool.begin().await.map_err(map_sqlx_error)?;
        sqlx::query!("DELETE FROM session_tokens WHERE did = $1", did.as_str())
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;
        sqlx::query!("DELETE FROM records WHERE repo_id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;
        sqlx::query!("DELETE FROM repos WHERE user_id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;
        sqlx::query!("DELETE FROM blobs WHERE created_by_user = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;
        sqlx::query!("DELETE FROM user_keys WHERE user_id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;
        sqlx::query!("DELETE FROM app_passwords WHERE user_id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;
        sqlx::query!(
            "DELETE FROM account_deletion_requests WHERE did = $1",
            did.as_str()
        )
        .execute(&mut *tx)
        .await
        .map_err(map_sqlx_error)?;
        sqlx::query!("DELETE FROM users WHERE id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;
        tx.commit().await.map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn set_user_takedown(
        &self,
        did: &Did,
        takedown_ref: Option<&str>,
    ) -> Result<bool, DbError> {
        let result = sqlx::query!(
            "UPDATE users SET takedown_ref = $1 WHERE did = $2",
            takedown_ref,
            did.as_str()
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(result.rows_affected() > 0)
    }

    async fn admin_delete_account_complete(&self, user_id: Uuid, did: &Did) -> Result<(), DbError> {
        let mut tx = self.pool.begin().await.map_err(map_sqlx_error)?;
        sqlx::query!("DELETE FROM session_tokens WHERE did = $1", did.as_str())
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;
        sqlx::query!(
            "DELETE FROM used_refresh_tokens WHERE session_id IN (SELECT id FROM session_tokens WHERE did = $1)",
            did.as_str()
        )
        .execute(&mut *tx)
        .await
        .ok();
        sqlx::query!("DELETE FROM records WHERE repo_id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;
        sqlx::query!("DELETE FROM repos WHERE user_id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;
        sqlx::query!("DELETE FROM blobs WHERE created_by_user = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;
        sqlx::query!("DELETE FROM app_passwords WHERE user_id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;
        sqlx::query!(
            "DELETE FROM invite_code_uses WHERE used_by_user = $1",
            user_id
        )
        .execute(&mut *tx)
        .await
        .ok();
        sqlx::query!(
            "DELETE FROM invite_codes WHERE created_by_user = $1",
            user_id
        )
        .execute(&mut *tx)
        .await
        .ok();
        sqlx::query!("DELETE FROM user_keys WHERE user_id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;
        sqlx::query!("DELETE FROM users WHERE id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;
        tx.commit().await.map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn get_user_for_did_doc(&self, did: &Did) -> Result<Option<UserForDidDoc>, DbError> {
        let row = sqlx::query!(
            "SELECT id, handle, deactivated_at FROM users WHERE did = $1",
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        row.map(|r| {
            Ok(UserForDidDoc {
                id: r.id,
                handle: column(r.handle, col::USERS_HANDLE)?,
                deactivated_at: r.deactivated_at,
            })
        })
        .transpose()
    }

    async fn get_user_for_did_doc_build(
        &self,
        did: &Did,
    ) -> Result<Option<UserForDidDocBuild>, DbError> {
        let row = sqlx::query!(
            "SELECT id, handle, migrated_to_pds FROM users WHERE did = $1",
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        row.map(|r| {
            Ok(UserForDidDocBuild {
                id: r.id,
                handle: column(r.handle, col::USERS_HANDLE)?,
                migrated_to_pds: r.migrated_to_pds,
            })
        })
        .transpose()
    }

    async fn upsert_did_web_overrides(
        &self,
        user_id: Uuid,
        verification_methods: Option<serde_json::Value>,
        also_known_as: Option<Vec<String>>,
    ) -> Result<(), DbError> {
        let now = chrono::Utc::now();
        sqlx::query!(
            r#"
            INSERT INTO did_web_overrides (user_id, verification_methods, also_known_as, updated_at)
            VALUES ($1, COALESCE($2, '[]'::jsonb), COALESCE($3, '{}'::text[]), $4)
            ON CONFLICT (user_id) DO UPDATE SET
                verification_methods = CASE WHEN $2 IS NOT NULL THEN $2 ELSE did_web_overrides.verification_methods END,
                also_known_as = CASE WHEN $3 IS NOT NULL THEN $3 ELSE did_web_overrides.also_known_as END,
                updated_at = $4
            "#,
            user_id,
            verification_methods,
            also_known_as.as_deref(),
            now
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn update_migrated_to_pds(&self, did: &Did, endpoint: &str) -> Result<(), DbError> {
        let now = chrono::Utc::now();
        sqlx::query!(
            "UPDATE users SET migrated_to_pds = $1, migrated_at = $2 WHERE did = $3",
            endpoint,
            now,
            did.as_str()
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn get_user_for_passkey_setup(
        &self,
        did: &Did,
    ) -> Result<Option<UserForPasskeySetup>, DbError> {
        let row = sqlx::query!(
            r#"SELECT id, handle, recovery_token, recovery_token_expires_at, password_required
               FROM users WHERE did = $1"#,
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        row.map(|r| {
            Ok(UserForPasskeySetup {
                id: r.id,
                handle: column(r.handle, col::USERS_HANDLE)?,
                recovery_token: r.recovery_token,
                recovery_token_expires_at: r.recovery_token_expires_at,
                password_required: r.password_required,
            })
        })
        .transpose()
    }

    async fn get_user_for_passkey_recovery(
        &self,
        identifier: &str,
        normalized_handle: &str,
    ) -> Result<Option<UserForPasskeyRecovery>, DbError> {
        let row = sqlx::query!(
            "SELECT id, did, handle, password_required FROM users WHERE LOWER(email) = $1 OR handle = $2",
            identifier,
            normalized_handle
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        row.map(|r| {
            Ok(UserForPasskeyRecovery {
                id: r.id,
                did: column(r.did, col::USERS_DID)?,
                handle: column(r.handle, col::USERS_HANDLE)?,
                password_required: r.password_required,
            })
        })
        .transpose()
    }

    async fn set_recovery_token(
        &self,
        did: &Did,
        token_hash: &str,
        expires_at: DateTime<Utc>,
    ) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET recovery_token = $1, recovery_token_expires_at = $2 WHERE did = $3",
            token_hash,
            expires_at,
            did.as_str()
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn get_user_for_recovery(&self, did: &Did) -> Result<Option<UserForRecovery>, DbError> {
        let row = sqlx::query!(
            "SELECT id, did, preferred_comms_channel as \"preferred_comms_channel: CommsChannel\", recovery_token, recovery_token_expires_at FROM users WHERE did = $1",
            did.as_str()
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        row.map(|r| {
            Ok(UserForRecovery {
                id: r.id,
                did: column(r.did, col::USERS_DID)?,
                preferred_comms_channel: r.preferred_comms_channel,
                recovery_token: r.recovery_token,
                recovery_token_expires_at: r.recovery_token_expires_at,
            })
        })
        .transpose()
    }

    async fn get_accounts_scheduled_for_deletion(
        &self,
        limit: i64,
    ) -> Result<Vec<tranquil_db_traits::ScheduledDeletionAccount>, DbError> {
        let rows = sqlx::query!(
            r#"
            SELECT id, did, handle
            FROM users
            WHERE delete_after IS NOT NULL
              AND delete_after < NOW()
              AND deactivated_at IS NOT NULL
            LIMIT $1
            "#,
            limit
        )
        .fetch_all(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(rows
            .into_iter()
            .filter_map(|r| {
                Some(tranquil_db_traits::ScheduledDeletionAccount {
                    id: r.id,
                    did: legacy_column(r.did, col::USERS_DID)?,
                    handle: legacy_column(r.handle, col::USERS_HANDLE)?,
                })
            })
            .collect())
    }

    async fn delete_account_with_firehose(&self, user_id: Uuid, did: &Did) -> Result<(), DbError> {
        let mut tx = self.pool.begin().await.map_err(map_sqlx_error)?;

        sqlx::query!("DELETE FROM blobs WHERE created_by_user = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        sqlx::query!("DELETE FROM record_blobs WHERE repo_id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        sqlx::query!("DELETE FROM records WHERE repo_id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        sqlx::query!("DELETE FROM repos WHERE user_id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        sqlx::query!("DELETE FROM user_blocks WHERE user_id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        sqlx::query!("DELETE FROM user_keys WHERE user_id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        sqlx::query!("DELETE FROM session_tokens WHERE did = $1", did.as_str())
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        sqlx::query!("DELETE FROM app_passwords WHERE user_id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        sqlx::query!("DELETE FROM passkeys WHERE did = $1", did.as_str())
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        sqlx::query!("DELETE FROM user_totp WHERE did = $1", did.as_str())
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        sqlx::query!("DELETE FROM backup_codes WHERE did = $1", did.as_str())
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        sqlx::query!(
            "DELETE FROM webauthn_challenges WHERE did = $1",
            did.as_str()
        )
        .execute(&mut *tx)
        .await
        .map_err(map_sqlx_error)?;

        sqlx::query!(
            "DELETE FROM account_deletion_requests WHERE did = $1",
            did.as_str()
        )
        .execute(&mut *tx)
        .await
        .map_err(map_sqlx_error)?;

        sqlx::query!("DELETE FROM users WHERE id = $1", user_id)
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        let event_id: i64 = sqlx::query_scalar!(
            r#"
            INSERT INTO repo_seq (did, event_type, active, status)
            VALUES ($1, 'account', false, 'deleted')
            RETURNING id
            "#,
            did.as_str()
        )
        .fetch_one(&mut *tx)
        .await
        .map_err(map_sqlx_error)?;

        sqlx::query!(
            "DELETE FROM repo_seq WHERE did = $1 AND id <> $2",
            did.as_str(),
            event_id
        )
        .execute(&mut *tx)
        .await
        .map_err(map_sqlx_error)?;

        tx.commit().await.map_err(map_sqlx_error)?;

        sqlx::query!("NOTIFY repo_updates")
            .execute(&self.pool)
            .await
            .map_err(map_sqlx_error)?;

        Ok(())
    }

    async fn create_password_account(
        &self,
        input: &tranquil_db_traits::CreatePasswordAccountInput,
    ) -> Result<
        tranquil_db_traits::CreatePasswordAccountResult,
        tranquil_db_traits::CreateAccountError,
    > {
        tracing::info!(did = %input.did, handle = %input.handle, "create_password_account: starting transaction");
        let mut tx = self.pool.begin().await.map_err(|e: sqlx::Error| {
            tracing::error!(
                "create_password_account: failed to begin transaction: {}",
                e
            );
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        let is_first_user: bool = sqlx::query_scalar!("SELECT COUNT(*) as count FROM users")
            .fetch_one(&mut *tx)
            .await
            .map(|c| c.unwrap_or(0) == 0)
            .unwrap_or(false);

        let user_insert: Result<(uuid::Uuid,), _> = sqlx::query_as(
            r#"INSERT INTO users (
                handle, email, did, password_hash,
                preferred_comms_channel,
                discord_username, telegram_username, signal_username,
                is_admin, deactivated_at, inbound_migration, email_verified
            ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, FALSE) RETURNING id"#,
        )
        .bind(input.handle.as_str())
        .bind(&input.email)
        .bind(input.did.as_str())
        .bind(&input.password_hash)
        .bind(input.preferred_comms_channel)
        .bind(&input.discord_username)
        .bind(&input.telegram_username)
        .bind(&input.signal_username)
        .bind(is_first_user)
        .bind(input.deactivated_at)
        .bind(input.inbound_migration)
        .fetch_one(&mut *tx)
        .await;

        let user_id = match user_insert {
            Ok((id,)) => {
                tracing::info!(did = %input.did, user_id = %id, "create_password_account: user row inserted");
                id
            }
            Err(e) => {
                tracing::error!(did = %input.did, error = %e, "create_password_account: user insert failed");
                if let Some(db_err) = e.as_database_error()
                    && db_err.code().as_deref() == Some("23505")
                {
                    let constraint = db_err.constraint().unwrap_or("");
                    if constraint.contains("handle") {
                        return Err(tranquil_db_traits::CreateAccountError::HandleTaken);
                    } else if constraint.contains("email") {
                        return Err(tranquil_db_traits::CreateAccountError::EmailTaken);
                    } else if constraint.contains("did") {
                        return Err(tranquil_db_traits::CreateAccountError::DidExists);
                    }
                }
                return Err(tranquil_db_traits::CreateAccountError::Database(
                    e.to_string(),
                ));
            }
        };

        sqlx::query!(
            "INSERT INTO user_keys (user_id, key_bytes, encryption_version, encrypted_at) VALUES ($1, $2, $3, NOW())",
            user_id,
            &input.encrypted_key_bytes[..],
            input.encryption_version
        )
        .execute(&mut *tx)
        .await
        .map_err(|e: sqlx::Error| tranquil_db_traits::CreateAccountError::Database(e.to_string()))?;

        if let Some(key_id) = input.reserved_key_id {
            sqlx::query!(
                "UPDATE reserved_signing_keys SET used_at = NOW() WHERE id = $1",
                key_id
            )
            .execute(&mut *tx)
            .await
            .map_err(|e: sqlx::Error| {
                tranquil_db_traits::CreateAccountError::Database(e.to_string())
            })?;
        }

        sqlx::query!(
            "INSERT INTO repos (user_id, repo_root_cid, repo_rev) VALUES ($1, $2, $3)",
            user_id,
            input.commit_cid.as_str(),
            input.repo_rev.as_str()
        )
        .execute(&mut *tx)
        .await
        .map_err(|e: sqlx::Error| {
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        sqlx::query(
            r#"
            INSERT INTO user_blocks (user_id, block_cid, repo_rev)
            SELECT $1, block_cid, $3 FROM UNNEST($2::bytea[]) AS t(block_cid)
            ON CONFLICT (user_id, block_cid) DO NOTHING
            "#,
        )
        .bind(user_id)
        .bind(&input.genesis_block_cids)
        .bind(&input.repo_rev)
        .execute(&mut *tx)
        .await
        .map_err(|e: sqlx::Error| {
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        if let Some(code) = &input.invite_code {
            consume_invite_code(&mut tx, code, user_id).await?;
        }

        if let Some(birthdate_pref) = &input.birthdate_pref {
            let _ = sqlx::query!(
                "INSERT INTO account_preferences (user_id, name, value_json) VALUES ($1, $2, $3)",
                user_id,
                "app.bsky.actor.defs#personalDetailsPref",
                birthdate_pref
            )
            .execute(&mut *tx)
            .await;
        }

        tracing::info!(did = %input.did, user_id = %user_id, "create_password_account: committing transaction");
        tx.commit().await.map_err(|e: sqlx::Error| {
            tracing::error!(did = %input.did, user_id = %user_id, error = %e, "create_password_account: commit failed");
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;
        tracing::info!(did = %input.did, user_id = %user_id, "create_password_account: transaction committed successfully");

        Ok(tranquil_db_traits::CreatePasswordAccountResult {
            user_id,
            is_admin: is_first_user,
        })
    }

    async fn create_delegated_account(
        &self,
        input: &tranquil_db_traits::CreateDelegatedAccountInput,
    ) -> Result<uuid::Uuid, tranquil_db_traits::CreateAccountError> {
        let mut tx = self.pool.begin().await.map_err(|e: sqlx::Error| {
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        let user_insert: Result<(uuid::Uuid,), _> = sqlx::query_as(
            r#"INSERT INTO users (
                handle, email, did, password_hash, password_required,
                account_type, preferred_comms_channel
            ) VALUES ($1, $2, $3, NULL, FALSE, 'delegated'::account_type, 'email'::comms_channel) RETURNING id"#,
        )
        .bind(input.handle.as_str())
        .bind(&input.email)
        .bind(input.did.as_str())
        .fetch_one(&mut *tx)
        .await;

        let user_id = match user_insert {
            Ok((id,)) => id,
            Err(e) => {
                if let Some(db_err) = e.as_database_error()
                    && db_err.code().as_deref() == Some("23505")
                {
                    let constraint = db_err.constraint().unwrap_or("");
                    if constraint.contains("handle") {
                        return Err(tranquil_db_traits::CreateAccountError::HandleTaken);
                    } else if constraint.contains("email") {
                        return Err(tranquil_db_traits::CreateAccountError::EmailTaken);
                    }
                }
                return Err(tranquil_db_traits::CreateAccountError::Database(
                    e.to_string(),
                ));
            }
        };

        sqlx::query!(
            "INSERT INTO user_keys (user_id, key_bytes, encryption_version, encrypted_at) VALUES ($1, $2, $3, NOW())",
            user_id,
            &input.encrypted_key_bytes[..],
            input.encryption_version
        )
        .execute(&mut *tx)
        .await
        .map_err(|e: sqlx::Error| tranquil_db_traits::CreateAccountError::Database(e.to_string()))?;

        sqlx::query!(
            r#"INSERT INTO account_delegations (delegated_did, controller_did, granted_scopes, granted_by)
               VALUES ($1, $2, $3, $4)"#,
            input.did.as_str(),
            input.controller_did.as_str(),
            &input.controller_scopes,
            input.controller_did.as_str()
        )
        .execute(&mut *tx)
        .await
        .map_err(|e: sqlx::Error| tranquil_db_traits::CreateAccountError::Database(e.to_string()))?;

        sqlx::query!(
            "INSERT INTO repos (user_id, repo_root_cid, repo_rev) VALUES ($1, $2, $3)",
            user_id,
            input.commit_cid.as_str(),
            input.repo_rev.as_str()
        )
        .execute(&mut *tx)
        .await
        .map_err(|e: sqlx::Error| {
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        sqlx::query(
            r#"
            INSERT INTO user_blocks (user_id, block_cid, repo_rev)
            SELECT $1, block_cid, $3 FROM UNNEST($2::bytea[]) AS t(block_cid)
            ON CONFLICT (user_id, block_cid) DO NOTHING
            "#,
        )
        .bind(user_id)
        .bind(&input.genesis_block_cids)
        .bind(&input.repo_rev)
        .execute(&mut *tx)
        .await
        .map_err(|e: sqlx::Error| {
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        tx.commit().await.map_err(|e: sqlx::Error| {
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        Ok(user_id)
    }

    async fn create_passkey_account(
        &self,
        input: &tranquil_db_traits::CreatePasskeyAccountInput,
    ) -> Result<
        tranquil_db_traits::CreatePasswordAccountResult,
        tranquil_db_traits::CreateAccountError,
    > {
        let mut tx = self.pool.begin().await.map_err(|e: sqlx::Error| {
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        let is_first_user: bool = sqlx::query_scalar!("SELECT COUNT(*) as count FROM users")
            .fetch_one(&mut *tx)
            .await
            .map(|c| c.unwrap_or(0) == 0)
            .unwrap_or(false);

        let user_insert: Result<(uuid::Uuid,), _> = sqlx::query_as(
            r#"INSERT INTO users (
                handle, email, did, password_hash, password_required,
                preferred_comms_channel,
                discord_username, telegram_username, signal_username,
                recovery_token, recovery_token_expires_at,
                is_admin, deactivated_at
            ) VALUES ($1, $2, $3, NULL, FALSE, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING id"#,
        )
        .bind(input.handle.as_str())
        .bind(&input.email)
        .bind(input.did.as_str())
        .bind(input.preferred_comms_channel)
        .bind(&input.discord_username)
        .bind(&input.telegram_username)
        .bind(&input.signal_username)
        .bind(&input.setup_token_hash)
        .bind(input.setup_expires_at)
        .bind(is_first_user)
        .bind(input.deactivated_at)
        .fetch_one(&mut *tx)
        .await;

        let user_id = match user_insert {
            Ok((id,)) => id,
            Err(e) => {
                if let Some(db_err) = e.as_database_error()
                    && db_err.code().as_deref() == Some("23505")
                {
                    let constraint = db_err.constraint().unwrap_or("");
                    if constraint.contains("handle") {
                        return Err(tranquil_db_traits::CreateAccountError::HandleTaken);
                    } else if constraint.contains("email") {
                        return Err(tranquil_db_traits::CreateAccountError::EmailTaken);
                    }
                }
                return Err(tranquil_db_traits::CreateAccountError::Database(
                    e.to_string(),
                ));
            }
        };

        sqlx::query!(
            "INSERT INTO user_keys (user_id, key_bytes, encryption_version, encrypted_at) VALUES ($1, $2, $3, NOW())",
            user_id,
            &input.encrypted_key_bytes[..],
            input.encryption_version
        )
        .execute(&mut *tx)
        .await
        .map_err(|e: sqlx::Error| tranquil_db_traits::CreateAccountError::Database(e.to_string()))?;

        if let Some(key_id) = input.reserved_key_id {
            sqlx::query!(
                "UPDATE reserved_signing_keys SET used_at = NOW() WHERE id = $1",
                key_id
            )
            .execute(&mut *tx)
            .await
            .map_err(|e: sqlx::Error| {
                tranquil_db_traits::CreateAccountError::Database(e.to_string())
            })?;
        }

        sqlx::query!(
            "INSERT INTO repos (user_id, repo_root_cid, repo_rev) VALUES ($1, $2, $3)",
            user_id,
            input.commit_cid.as_str(),
            input.repo_rev.as_str()
        )
        .execute(&mut *tx)
        .await
        .map_err(|e: sqlx::Error| {
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        sqlx::query(
            r#"
            INSERT INTO user_blocks (user_id, block_cid, repo_rev)
            SELECT $1, block_cid, $3 FROM UNNEST($2::bytea[]) AS t(block_cid)
            ON CONFLICT (user_id, block_cid) DO NOTHING
            "#,
        )
        .bind(user_id)
        .bind(&input.genesis_block_cids)
        .bind(&input.repo_rev)
        .execute(&mut *tx)
        .await
        .map_err(|e: sqlx::Error| {
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        if let Some(code) = &input.invite_code {
            consume_invite_code(&mut tx, code, user_id).await?;
        }

        if let Some(birthdate_pref) = &input.birthdate_pref {
            let _ = sqlx::query!(
                "INSERT INTO account_preferences (user_id, name, value_json) VALUES ($1, $2, $3)",
                user_id,
                "app.bsky.actor.defs#personalDetailsPref",
                birthdate_pref
            )
            .execute(&mut *tx)
            .await;
        }

        tx.commit().await.map_err(|e: sqlx::Error| {
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        Ok(tranquil_db_traits::CreatePasswordAccountResult {
            user_id,
            is_admin: is_first_user,
        })
    }

    async fn create_sso_account(
        &self,
        input: &tranquil_db_traits::CreateSsoAccountInput,
    ) -> Result<
        tranquil_db_traits::CreatePasswordAccountResult,
        tranquil_db_traits::CreateAccountError,
    > {
        let mut tx = self.pool.begin().await.map_err(|e: sqlx::Error| {
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        let token_consumed: Option<(String,)> = sqlx::query_as(
            r#"
            DELETE FROM sso_pending_registration
            WHERE token = $1 AND expires_at > NOW()
            RETURNING token
            "#,
        )
        .bind(&input.pending_registration_token)
        .fetch_optional(&mut *tx)
        .await
        .map_err(|e: sqlx::Error| {
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        if token_consumed.is_none() {
            return Err(tranquil_db_traits::CreateAccountError::InvalidToken);
        }

        let is_first_user: bool = sqlx::query_scalar!("SELECT COUNT(*) as count FROM users")
            .fetch_one(&mut *tx)
            .await
            .map(|c| c.unwrap_or(0) == 0)
            .unwrap_or(false);

        let user_insert: Result<(uuid::Uuid,), _> = sqlx::query_as(
            r#"INSERT INTO users (
                handle, email, did, password_hash, password_required,
                preferred_comms_channel, discord_username, telegram_username, signal_username,
                is_admin
            ) VALUES ($1, $2, $3, NULL, FALSE, $4, $5, $6, $7, $8) RETURNING id"#,
        )
        .bind(input.handle.as_str())
        .bind(&input.email)
        .bind(input.did.as_str())
        .bind(input.preferred_comms_channel)
        .bind(&input.discord_username)
        .bind(&input.telegram_username)
        .bind(&input.signal_username)
        .bind(is_first_user)
        .fetch_one(&mut *tx)
        .await;

        let user_id = match user_insert {
            Ok((id,)) => id,
            Err(e) => {
                if let Some(db_err) = e.as_database_error()
                    && db_err.code().as_deref() == Some("23505")
                {
                    let constraint = db_err.constraint().unwrap_or("");
                    if constraint.contains("handle") {
                        return Err(tranquil_db_traits::CreateAccountError::HandleTaken);
                    } else if constraint.contains("email") {
                        return Err(tranquil_db_traits::CreateAccountError::EmailTaken);
                    }
                }
                return Err(tranquil_db_traits::CreateAccountError::Database(
                    e.to_string(),
                ));
            }
        };

        sqlx::query!(
            "INSERT INTO user_keys (user_id, key_bytes, encryption_version, encrypted_at) VALUES ($1, $2, $3, NOW())",
            user_id,
            &input.encrypted_key_bytes[..],
            input.encryption_version
        )
        .execute(&mut *tx)
        .await
        .map_err(|e: sqlx::Error| tranquil_db_traits::CreateAccountError::Database(e.to_string()))?;

        sqlx::query!(
            "INSERT INTO repos (user_id, repo_root_cid, repo_rev) VALUES ($1, $2, $3)",
            user_id,
            input.commit_cid.as_str(),
            input.repo_rev.as_str()
        )
        .execute(&mut *tx)
        .await
        .map_err(|e: sqlx::Error| {
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        sqlx::query(
            r#"
            INSERT INTO user_blocks (user_id, block_cid, repo_rev)
            SELECT $1, block_cid, $3 FROM UNNEST($2::bytea[]) AS t(block_cid)
            ON CONFLICT (user_id, block_cid) DO NOTHING
            "#,
        )
        .bind(user_id)
        .bind(&input.genesis_block_cids)
        .bind(&input.repo_rev)
        .execute(&mut *tx)
        .await
        .map_err(|e: sqlx::Error| {
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        if let Some(code) = &input.invite_code {
            consume_invite_code(&mut tx, code, user_id).await?;
        }

        if let Some(birthdate_pref) = &input.birthdate_pref {
            let _ = sqlx::query!(
                "INSERT INTO account_preferences (user_id, name, value_json) VALUES ($1, $2, $3)",
                user_id,
                "app.bsky.actor.defs#personalDetailsPref",
                birthdate_pref
            )
            .execute(&mut *tx)
            .await;
        }

        sqlx::query!(
            r#"
            INSERT INTO external_identities (did, provider, provider_user_id, provider_username, provider_email, provider_email_verified)
            VALUES ($1, $2, $3, $4, $5, $6)
            "#,
            input.did.as_str(),
            input.sso_provider as SsoProviderType,
            &input.sso_provider_user_id,
            input.sso_provider_username.as_deref(),
            input.sso_provider_email.as_deref(),
            input.sso_provider_email_verified,
        )
        .execute(&mut *tx)
        .await
        .map_err(|e: sqlx::Error| {
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        tx.commit().await.map_err(|e: sqlx::Error| {
            tranquil_db_traits::CreateAccountError::Database(e.to_string())
        })?;

        Ok(tranquil_db_traits::CreatePasswordAccountResult {
            user_id,
            is_admin: is_first_user,
        })
    }

    async fn reactivate_migration_account(
        &self,
        input: &tranquil_db_traits::MigrationReactivationInput,
    ) -> Result<
        tranquil_db_traits::ReactivatedAccountInfo,
        tranquil_db_traits::MigrationReactivationError,
    > {
        let mut tx =
            self.pool.begin().await.map_err(|e| {
                tranquil_db_traits::MigrationReactivationError::Database(e.to_string())
            })?;

        let existing: Option<(uuid::Uuid, String, Option<chrono::DateTime<chrono::Utc>>)> =
            sqlx::query_as(
                "SELECT id, handle, deactivated_at FROM users WHERE did = $1 FOR UPDATE",
            )
            .bind(input.did.as_str())
            .fetch_optional(&mut *tx)
            .await
            .map_err(|e| tranquil_db_traits::MigrationReactivationError::Database(e.to_string()))?;

        let (account_id, old_handle, deactivated_at) =
            existing.ok_or(tranquil_db_traits::MigrationReactivationError::NotFound)?;

        if deactivated_at.is_none() {
            return Err(tranquil_db_traits::MigrationReactivationError::NotDeactivated);
        }

        let update_result: Result<_, sqlx::Error> = if let Some(ref new_email) = input.new_email {
            sqlx::query(
                "UPDATE users SET handle = $1, email = $2, email_verified = false WHERE id = $3",
            )
            .bind(input.new_handle.as_str())
            .bind(new_email)
            .bind(account_id)
            .execute(&mut *tx)
            .await
        } else {
            sqlx::query("UPDATE users SET handle = $1 WHERE id = $2")
                .bind(input.new_handle.as_str())
                .bind(account_id)
                .execute(&mut *tx)
                .await
        };

        if let Err(e) = update_result {
            if let Some(db_err) = e.as_database_error()
                && db_err
                    .constraint()
                    .map(|c| c.contains("handle"))
                    .unwrap_or(false)
            {
                return Err(tranquil_db_traits::MigrationReactivationError::HandleTaken);
            }
            return Err(tranquil_db_traits::MigrationReactivationError::Database(
                e.to_string(),
            ));
        }

        let old_handle = legacy_column(old_handle, col::USERS_HANDLE);

        tx.commit()
            .await
            .map_err(|e| tranquil_db_traits::MigrationReactivationError::Database(e.to_string()))?;

        Ok(tranquil_db_traits::ReactivatedAccountInfo {
            user_id: account_id,
            old_handle,
        })
    }

    async fn check_handle_available_for_new_account(
        &self,
        handle: &Handle,
    ) -> Result<bool, DbError> {
        let exists: Option<(i32,)> = sqlx::query_as(
            r#"
            SELECT 1 FROM users WHERE handle = $1 AND deactivated_at IS NULL
            UNION ALL
            SELECT 1 FROM handle_reservations WHERE handle = $1 AND expires_at > NOW()
            LIMIT 1
            "#,
        )
        .bind(handle.as_str())
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(exists.is_none())
    }

    async fn reserve_handle(&self, handle: &Handle, reserved_by: &str) -> Result<bool, DbError> {
        sqlx::query!("DELETE FROM handle_reservations WHERE expires_at <= NOW()")
            .execute(&self.pool)
            .await
            .map_err(map_sqlx_error)?;

        let result = sqlx::query!(
            r#"
            INSERT INTO handle_reservations (handle, reserved_by)
            SELECT $1, $2
            WHERE NOT EXISTS (
                SELECT 1 FROM users WHERE handle = $1 AND deactivated_at IS NULL
            )
            AND NOT EXISTS (
                SELECT 1 FROM handle_reservations WHERE handle = $1 AND expires_at > NOW()
            )
            "#,
            handle.as_str(),
            reserved_by,
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(result.rows_affected() > 0)
    }

    async fn release_handle_reservation(&self, handle: &Handle) -> Result<(), DbError> {
        sqlx::query!(
            "DELETE FROM handle_reservations WHERE handle = $1",
            handle.as_str()
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(())
    }

    async fn cleanup_expired_handle_reservations(&self) -> Result<u64, DbError> {
        let result = sqlx::query!("DELETE FROM handle_reservations WHERE expires_at <= NOW()")
            .execute(&self.pool)
            .await
            .map_err(map_sqlx_error)?;

        Ok(result.rows_affected())
    }

    async fn complete_passkey_setup(
        &self,
        input: &tranquil_db_traits::CompletePasskeySetupInput,
    ) -> Result<(), DbError> {
        let mut tx = self.pool.begin().await.map_err(map_sqlx_error)?;

        sqlx::query!(
            "INSERT INTO app_passwords (user_id, name, password_hash, privileged) VALUES ($1, $2, $3, FALSE)",
            input.user_id,
            input.app_password_name,
            input.app_password_hash.as_str()
        )
        .execute(&mut *tx)
        .await
        .map_err(map_sqlx_error)?;

        sqlx::query!(
            "UPDATE users SET recovery_token = NULL, recovery_token_expires_at = NULL WHERE did = $1",
            input.did.as_str()
        )
        .execute(&mut *tx)
        .await
        .map_err(map_sqlx_error)?;

        tx.commit().await.map_err(map_sqlx_error)?;

        Ok(())
    }

    async fn recover_passkey_account(
        &self,
        input: &tranquil_db_traits::RecoverPasskeyAccountInput,
    ) -> Result<tranquil_db_traits::RecoverPasskeyAccountResult, DbError> {
        let mut tx = self.pool.begin().await.map_err(map_sqlx_error)?;

        sqlx::query!(
            "UPDATE users SET password_hash = $1, password_required = TRUE, recovery_token = NULL, recovery_token_expires_at = NULL WHERE did = $2",
            input.password_hash.as_str(),
            input.did.as_str()
        )
        .execute(&mut *tx)
        .await
        .map_err(map_sqlx_error)?;

        let deleted = sqlx::query!("DELETE FROM passkeys WHERE did = $1", input.did.as_str())
            .execute(&mut *tx)
            .await
            .map_err(map_sqlx_error)?;

        tx.commit().await.map_err(map_sqlx_error)?;

        Ok(tranquil_db_traits::RecoverPasskeyAccountResult {
            passkeys_deleted: deleted.rows_affected(),
        })
    }

    async fn set_unverified_telegram(
        &self,
        user_id: Uuid,
        telegram_username: &str,
    ) -> Result<(), DbError> {
        sqlx::query!(
            r#"UPDATE users SET
                telegram_username = $1,
                telegram_verified = CASE WHEN LOWER(telegram_username) = LOWER($1) THEN telegram_verified ELSE FALSE END,
                telegram_chat_id = CASE WHEN LOWER(telegram_username) = LOWER($1) THEN telegram_chat_id ELSE NULL END,
                updated_at = NOW()
            WHERE id = $2"#,
            telegram_username,
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn set_unverified_signal(
        &self,
        user_id: Uuid,
        signal_username: &str,
    ) -> Result<(), DbError> {
        sqlx::query!(
            r#"UPDATE users SET
                signal_username = $1,
                signal_verified = CASE WHEN LOWER(signal_username) = LOWER($1) THEN signal_verified ELSE FALSE END,
                updated_at = NOW()
            WHERE id = $2"#,
            signal_username,
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn set_unverified_discord(
        &self,
        user_id: Uuid,
        discord_username: &str,
    ) -> Result<(), DbError> {
        sqlx::query!(
            r#"UPDATE users SET
                discord_username = $1,
                discord_verified = CASE WHEN LOWER(discord_username) = LOWER($1) THEN discord_verified ELSE FALSE END,
                discord_id = CASE WHEN LOWER(discord_username) = LOWER($1) THEN discord_id ELSE NULL END,
                updated_at = NOW()
            WHERE id = $2"#,
            discord_username,
            user_id
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;
        Ok(())
    }

    async fn store_discord_user_id(
        &self,
        discord_username: &str,
        discord_id: &str,
        handle: Option<&Handle>,
    ) -> Result<Option<Uuid>, DbError> {
        let result = match handle {
            Some(h) => sqlx::query_scalar!(
                "UPDATE users SET discord_id = $2, discord_verified = TRUE, updated_at = NOW() WHERE LOWER(discord_username) = LOWER($1) AND discord_username IS NOT NULL AND handle = $3 RETURNING id",
                discord_username,
                discord_id,
                h.as_str()
            )
            .fetch_optional(&self.pool)
            .await
            .map_err(map_sqlx_error)?,
            None => {
                let mut tx = self.pool.begin().await.map_err(map_sqlx_error)?;

                let matching: Vec<uuid::Uuid> = match sqlx::query_scalar!(
                    "SELECT id FROM users WHERE LOWER(discord_username) = LOWER($1) AND discord_username IS NOT NULL AND deactivated_at IS NULL FOR UPDATE NOWAIT",
                    discord_username
                )
                .fetch_all(&mut *tx)
                .await
                {
                    Ok(ids) => ids,
                    Err(sqlx::Error::Database(ref db_err))
                        if db_err.code().as_deref() == Some("55P03") =>
                    {
                        return Err(DbError::LockContention);
                    }
                    Err(e) => return Err(map_sqlx_error(e)),
                };

                let result = match matching.len() {
                    0 => None,
                    1 => {
                        sqlx::query_scalar!(
                            "UPDATE users SET discord_id = $2, discord_verified = TRUE, updated_at = NOW() WHERE id = $1 RETURNING id",
                            matching[0],
                            discord_id
                        )
                        .fetch_optional(&mut *tx)
                        .await
                        .map_err(map_sqlx_error)?
                    }
                    _ => {
                        tx.rollback().await.ok();
                        return Err(DbError::Ambiguous(
                            "Multiple accounts use this Discord username. Type: /start your-handle.example.com".to_string(),
                        ));
                    }
                };

                tx.commit().await.map_err(map_sqlx_error)?;
                result
            }
        };
        Ok(result)
    }

    async fn store_telegram_chat_id(
        &self,
        telegram_username: &str,
        chat_id: i64,
        handle: Option<&Handle>,
    ) -> Result<Option<Uuid>, DbError> {
        let result = match handle {
            Some(h) => sqlx::query_scalar!(
                "UPDATE users SET telegram_chat_id = $2, telegram_verified = TRUE, updated_at = NOW() WHERE LOWER(telegram_username) = LOWER($1) AND telegram_username IS NOT NULL AND handle = $3 RETURNING id",
                telegram_username,
                chat_id,
                h.as_str()
            )
            .fetch_optional(&self.pool)
            .await
            .map_err(map_sqlx_error)?,
            None => sqlx::query_scalar!(
                r#"UPDATE users SET telegram_chat_id = $2, telegram_verified = TRUE, updated_at = NOW()
                WHERE id = (
                    SELECT id FROM users
                    WHERE LOWER(telegram_username) = LOWER($1) AND telegram_username IS NOT NULL AND deactivated_at IS NULL
                    LIMIT 1
                ) RETURNING id"#,
                telegram_username,
                chat_id
            )
            .fetch_optional(&self.pool)
            .await
            .map_err(map_sqlx_error)?,
        };
        Ok(result)
    }

    async fn get_telegram_chat_id(&self, user_id: Uuid) -> Result<Option<i64>, DbError> {
        let row = sqlx::query_scalar!("SELECT telegram_chat_id FROM users WHERE id = $1", user_id)
            .fetch_optional(&self.pool)
            .await
            .map_err(map_sqlx_error)?;
        Ok(row.flatten())
    }

    async fn get_password_reset_info(
        &self,
        email: &str,
    ) -> Result<Option<tranquil_db_traits::PasswordResetInfo>, DbError> {
        let row = sqlx::query!(
            "SELECT password_reset_code, password_reset_code_expires_at FROM users WHERE email = $1",
            email
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(row.map(|r| tranquil_db_traits::PasswordResetInfo {
            code: r.password_reset_code,
            expires_at: r.password_reset_code_expires_at,
        }))
    }

    async fn enable_totp_verified(
        &self,
        did: &Did,
        encrypted_secret: &[u8],
    ) -> Result<(), DbError> {
        sqlx::query!(
            r#"INSERT INTO user_totp (did, secret_encrypted, encryption_version, verified, created_at)
               VALUES ($1, $2, 1, TRUE, NOW())
               ON CONFLICT (did) DO UPDATE SET secret_encrypted = $2, verified = TRUE"#,
            did.as_str(),
            encrypted_secret
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(())
    }

    async fn set_two_factor_enabled(&self, did: &Did, enabled: bool) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET two_factor_enabled = $1 WHERE did = $2",
            enabled,
            did.as_str()
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(())
    }

    async fn expire_password_reset_code(&self, email: &str) -> Result<(), DbError> {
        sqlx::query!(
            "UPDATE users SET password_reset_code_expires_at = NOW() - INTERVAL '1 hour' WHERE email = $1",
            email
        )
        .execute(&self.pool)
        .await
        .map_err(map_sqlx_error)?;

        Ok(())
    }
}
