    @property
    def client_secret(self) -> str:
        return encryption.decrypt(self.client_secret_enc)

    @client_secret.setter
    def client_secret(self, value: str) -> None:
        self.client_secret_enc = encryption.encrypt(value)


class GmailAccount(Base, TimestampMixin):
    __tablename__ = "gmail_accounts"
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
    email = Column(String(320), nullable=False)
    display_name = Column(String(200), default="")
    status = Column(String(30), default="pending")  # pending|authorized|expired|revoked|error
    sending_method = Column(String(20), default="api")  # api|smtp
    auth_provider = Column(String(60), default="google")
    google_user_id = Column(String(120), default="")
    # Per-account config (administrator-configurable)
    daily_limit = Column(Integer, default=200)          # provider/configured daily cap
    campaign_limit = Column(Integer, default=200)       # per-account per-campaign cap
    sends_today = Column(Integer, default=0)
    last_send_date = Column(DateTime(timezone=True))
    cooldown_until = Column(DateTime(timezone=True))
    last_success_at = Column(DateTime(timezone=True))
    last_error = Column(Text, default="")
    error_count = Column(Integer, default=0)
    token_expiry = Column(DateTime(timezone=True))
    # Imported client config reference (optional; may use server-level config)
    oauth_config_id = Column(Integer, ForeignKey("oauth_client_configs.id", ondelete="SET NULL"))
    # Encrypted SMTP OAuth2 credentials mirror (kept in oauth_tokens; this is metadata only)
    is_active = Column(Boolean, default=True, nullable=False)
    revoked_by_user = Column(Boolean, default=False)
    revoked_at = Column(DateTime(timezone=True))

    user = relationship("User", back_populates="gmail_accounts")
    # Eager-loaded (joined) so async endpoints/workers can read account.oauth_token
    # without triggering a lazy-load IO (which raises MissingGreenlet in async sessions).
    oauth_token = relationship("OAuthToken", back_populates="account", uselist=False,
                               cascade="all, delete-orphan", lazy="joined")
====test send task fake====

def _make_template(db, user_id, body_html=None):
    from app.models import EmailTemplate
    t = EmailTemplate(user_id=user_id, name=f"tpl-{uuid.uuid4().hex[:6]}",
                      subject_hint="hint",
                      body_html=body_html or
                      "<p>Hi %FirstName%, total %RandomTotal%. "
                      "Invoice %RandomInvoiceNumber%.</p>")
    db.add(t)
    db.commit()
    return t


def _make_account(db, user_id, status="authorized", **over):
    from app.models import GmailAccount, OAuthToken
    a = GmailAccount(user_id=user_id, email=f"send-acc-{uuid.uuid4().hex[:8]}@gmail.com",
                     status=status, sending_method="api",
                     is_active=(status == "authorized"))
    for k, v in over.items():
        setattr(a, k, v)
    db.add(a)
    db.commit()
    if status == "authorized":
        db.add(OAuthToken(account_id=a.id, access_token=f"tok-{uuid.uuid4().hex[:6]}",
                          refresh_token=f"ref-{uuid.uuid4().hex[:6]}",
                          expires_at=datetime.now(timezone.utc) + timedelta(hours=1)))
        db.commit()
    return a


def _seed_sendable(db, **camp_over):
    """User + list(1) + subject + template + authorized account + campaign +
    materialized CampaignRecipient (pending) + SendJob. Returns ids dict."""
    from app.models import Campaign, CampaignRecipient, SendJob
    u = _make_user(db)
    rl, recs = _make_list(db, u.id, n=1)
    subj = _make_subject(db, u.id)
    tpl = _make_template(db, u.id)
    acc = _make_account(db, u.id)
    kw = dict(
        user_id=u.id, name=f"send-{uuid.uuid4().hex[:6]}", status="running",
