                             db: AsyncSession = Depends(get_db), request: Request = None):
    """Clear All: revoke tokens at Google (best-effort) and remove all locally saved
    Gmail account rows. Audit trail preserved."""
    rows = (await db.execute(select(GmailAccount).where(
        GmailAccount.user_id == user.id))).scalars().all()
    revoked = 0
    for account in rows:
        token = account.oauth_token
        if token:
            if gmail_service.revoke_token(token.refresh_token or token.access_token):
                revoked += 1
        await db.delete(account)  # token cascades; related FKs are SET NULL
    await db.commit()
    await log_audit(db, user.id, "gmail.clear_all", "gmail_account", None,
                    {"count": len(rows), "revoked_at_google": revoked},
                    request.client.host if request else None)
    return {"ok": True, "removed": len(rows), "revoked_at_google": revoked}


@router.post("/accounts/import-config")
async def import_client_config(file: UploadFile = File(...),
                               user: User = Depends(get_current_user_csrf),
                               db: AsyncSession = Depends(get_db), request: Request = None):
    """Import & validate a Google OAuth client_secret JSON (never echoed back)."""
    from app.core.config import settings
    content = await file.read()
    if len(content) > 1024 * 512:
        raise HTTPException(413, "File too large (max 512 KB)")
    if not file.filename.lower().endswith(".json"):
        raise HTTPException(400, "Only .json configuration files are accepted")
    try:
        parsed = gmail_service.parse_client_json(content)
    except gmail_service.GmailOauthError as e:
        raise HTTPException(400, str(e))
    row = OAuthClientConfig(
        name=parsed["project_id"] or file.filename[:100],
        user_id=user.id,
        client_id=parsed["client_id"],
        client_secret=parsed["client_secret"],  # encrypted via property setter
        project_id=parsed["project_id"],
        redirect_uri=f"{settings.BASE_URL}/auth/google/callback",
    )
    db.add(row)
    await db.commit()
    await log_audit(db, user.id, "oauth_config.imported", "oauth_client_config", row.id,
                    {"project": parsed["project_id"]}, request.client.host if request else None)
    return {"ok": True, "id": row.id, "project_id": parsed["project_id"],
            "client_id_preview": parsed["client_id"][:12] + "…",
            "redirect_uri": row.redirect_uri}


def _parse_bulk_smtp_lines(raw: str) -> list[tuple[str, str, str]]:
    """Parse free-form pasted lines into (raw_line, email, app_password) tuples.
    Accepts separators: ':' ',' '|' or whitespace. Blank lines / comments (#) skipped."""
    import re as _re
    out = []
    for line in raw.splitlines():
        line = line.strip()
        if not line or line.startswith("#"):
            continue
        parts = _re.split(r"[:,|\s]+", line, maxsplit=1)
        if len(parts) != 2:
            out.append((line, "", ""))
            continue
        email, pwd = parts[0].strip(), parts[1].strip()
        out.append((line, email, pwd))
    return out


@router.post("/accounts/bulk-smtp")
async def bulk_add_smtp_accounts(payload: BulkSmtpAdd,
