# AUTO-GENERATED FILE - DO NOT EDIT
# This file was automatically generated by the XDK build tool.
# Any manual changes will be overwritten on the next generation.

"""
Auto-generated posts client for the X API.

This module provides a client for interacting with the posts endpoints of the X API.

All methods, parameters, and response models are generated from the OpenAPI specification.

Generated automatically - do not edit manually.
"""

from __future__ import annotations
from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING, Iterator
import requests
import time


if TYPE_CHECKING:
    from ..client import Client
from .models import (
    GetInsights28hrResponse,
    GetLikingUsersResponse,
    SearchRecentResponse,
    GetQuotedResponse,
    HideReplyRequest,
    HideReplyResponse,
    GetByIdsResponse,
    CreateRequest,
    CreateResponse,
    GetInsightsHistoricalResponse,
    GetCountsRecentResponse,
    GetRepostedByResponse,
    GetAnalyticsResponse,
    GetCountsAllResponse,
    SearchAllResponse,
    GetByIdResponse,
    DeleteResponse,
    GetRepostsResponse,
)


class PostsClient:
    """Client for posts operations"""


    def __init__(self, client: Client):
        self.client = client


    def get_insights28hr(
        self,
        tweet_ids: List,
        granularity: str,
        requested_metrics: List,
        engagement_fields: List = None,
    ) -> GetInsights28hrResponse:
        """
        Get 28-hour Post insights
        Retrieves engagement metrics for specified Posts over the last 28 hours.
        Args:
            tweet_ids: List of PostIds for 28hr metrics.
            granularity: granularity of metrics response.
            requested_metrics: request metrics for historical request.
            engagement_fields: A comma separated list of Engagement fields to display.
            Returns:
            GetInsights28hrResponse: Response data
        """
        url = self.client.base_url + "/2/insights/28hr"
        # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
        # Priority: access_token > oauth2_session (for token refresh support)
        if self.client.access_token:
            # Use access_token directly as bearer token (matches TypeScript)
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
            # If we have oauth2_auth, check if token needs refresh
            if self.client.oauth2_auth and self.client.token:
                if self.client.is_token_expired():
                    self.client.refresh_token()
                    # Update access_token after refresh
                    if self.client.access_token:
                        self.client.session.headers["Authorization"] = (
                            f"Bearer {self.client.access_token}"
                        )
        elif self.client.oauth2_auth and self.client.token:
            # Fallback: use oauth2_session if available (for backward compatibility)
            # Check if token needs refresh
            if self.client.is_token_expired():
                self.client.refresh_token()
        headers = {}
        # Prepare request data
        json_data = None
        # Determine pagination parameter name
        pagination_param_name = "pagination_token"  # Default fallback
        # Start with provided pagination_token, or None for first page
        # Check if pagination_token parameter exists in the method signature
        current_pagination_token = None
        while True:
            # Build query parameters for this page
            page_params = {}
            if tweet_ids is not None:
                page_params["tweet_ids"] = ",".join(str(item) for item in tweet_ids)
            if granularity is not None:
                page_params["granularity"] = granularity
            if requested_metrics is not None:
                page_params["requested_metrics"] = ",".join(
                    str(item) for item in requested_metrics
                )
            if engagement_fields is not None:
                page_params["engagement.fields"] = ",".join(
                    str(item) for item in engagement_fields
                )
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Make the request
            # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
            response = self.client.session.get(
                url,
                params=page_params,
                headers=headers,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = GetInsights28hrResponse.model_validate(response_data)
            # Yield this page
            yield page_response
            # Extract next_token from response
            next_token = None
            try:
                # Try response.meta.next_token (most common pattern)
                if hasattr(page_response, "meta") and page_response.meta is not None:
                    meta = page_response.meta
                    # If meta is a Pydantic model, try to dump it
                    if hasattr(meta, "model_dump"):
                        try:
                            meta_dict = meta.model_dump()
                            next_token = meta_dict.get("next_token")
                        except (AttributeError, TypeError):
                            pass
                    # Otherwise try attribute access
                    if not next_token and hasattr(meta, "next_token"):
                        next_token = getattr(meta, "next_token", None)
                    # If meta is a dict, access it directly
                    if not next_token and isinstance(meta, dict):
                        next_token = meta.get("next_token")
            except (AttributeError, TypeError):
                pass
            # Try dict access if we have a dict
            if not next_token and isinstance(response_data, dict):
                try:
                    meta = response_data.get("meta")
                    if meta and isinstance(meta, dict):
                        next_token = meta.get("next_token")
                except (AttributeError, TypeError, KeyError):
                    pass
            # If no next_token, we're done
            if not next_token:
                break
            # Update token for next iteration
            current_pagination_token = next_token

            # Optional: Add rate limit backoff here if needed
            # time.sleep(0.1)  # Small delay to avoid rate limits


    def get_liking_users(
        self,
        id: Any,
        max_results: int = None,
        pagination_token: Any = None,
        user_fields: List = None,
        expansions: List = None,
        tweet_fields: List = None,
    ) -> Iterator[GetLikingUsersResponse]:
        """
        Get Liking Users
        Retrieves a list of Users who liked a specific Post by its ID.
        Args:
            id: A single Post ID.
            max_results: The maximum number of results.
            pagination_token: This parameter is used to get the next 'page' of results.
            user_fields: A comma separated list of User fields to display.
            expansions: A comma separated list of fields to expand.
            tweet_fields: A comma separated list of Tweet fields to display.
            Yields:
            GetLikingUsersResponse: One page of results at a time. Automatically handles pagination using next_token.
        Note:
            This method automatically paginates through all results. To get just the first page,
            you can call it once and break, or use the pagination_token parameter to start at a specific page.
        """
        url = self.client.base_url + "/2/tweets/{id}/liking_users"
        url = url.replace("{id}", str(id))
        # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
        # Priority: access_token > oauth2_session (for token refresh support)
        if self.client.access_token:
            # Use access_token directly as bearer token (matches TypeScript)
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
            # If we have oauth2_auth, check if token needs refresh
            if self.client.oauth2_auth and self.client.token:
                if self.client.is_token_expired():
                    self.client.refresh_token()
                    # Update access_token after refresh
                    if self.client.access_token:
                        self.client.session.headers["Authorization"] = (
                            f"Bearer {self.client.access_token}"
                        )
        elif self.client.oauth2_auth and self.client.token:
            # Fallback: use oauth2_session if available (for backward compatibility)
            # Check if token needs refresh
            if self.client.is_token_expired():
                self.client.refresh_token()
        headers = {}
        # Prepare request data
        json_data = None
        # Determine pagination parameter name
        pagination_param_name = "pagination_token"
        # Start with provided pagination_token, or None for first page
        # Check if pagination_token parameter exists in the method signature
        current_pagination_token = pagination_token
        while True:
            # Build query parameters for this page
            page_params = {}
            if max_results is not None:
                page_params["max_results"] = max_results
            if user_fields is not None:
                page_params["user.fields"] = ",".join(str(item) for item in user_fields)
            if expansions is not None:
                page_params["expansions"] = ",".join(str(item) for item in expansions)
            if tweet_fields is not None:
                page_params["tweet.fields"] = ",".join(
                    str(item) for item in tweet_fields
                )
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Make the request
            # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
            response = self.client.session.get(
                url,
                params=page_params,
                headers=headers,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = GetLikingUsersResponse.model_validate(response_data)
            # Yield this page
            yield page_response
            # Extract next_token from response
            next_token = None
            try:
                # Try response.meta.next_token (most common pattern)
                if hasattr(page_response, "meta") and page_response.meta is not None:
                    meta = page_response.meta
                    # If meta is a Pydantic model, try to dump it
                    if hasattr(meta, "model_dump"):
                        try:
                            meta_dict = meta.model_dump()
                            next_token = meta_dict.get("next_token")
                        except (AttributeError, TypeError):
                            pass
                    # Otherwise try attribute access
                    if not next_token and hasattr(meta, "next_token"):
                        next_token = getattr(meta, "next_token", None)
                    # If meta is a dict, access it directly
                    if not next_token and isinstance(meta, dict):
                        next_token = meta.get("next_token")
            except (AttributeError, TypeError):
                pass
            # Try dict access if we have a dict
            if not next_token and isinstance(response_data, dict):
                try:
                    meta = response_data.get("meta")
                    if meta and isinstance(meta, dict):
                        next_token = meta.get("next_token")
                except (AttributeError, TypeError, KeyError):
                    pass
            # If no next_token, we're done
            if not next_token:
                break
            # Update token for next iteration
            current_pagination_token = next_token

            # Optional: Add rate limit backoff here if needed
            # time.sleep(0.1)  # Small delay to avoid rate limits


    def search_recent(
        self,
        query: str,
        start_time: str = None,
        end_time: str = None,
        since_id: Any = None,
        until_id: Any = None,
        max_results: int = None,
        next_token: Any = None,
        pagination_token: Any = None,
        sort_order: str = None,
        tweet_fields: List = None,
        expansions: List = None,
        media_fields: List = None,
        poll_fields: List = None,
        user_fields: List = None,
        place_fields: List = None,
    ) -> Iterator[SearchRecentResponse]:
        """
        Search recent Posts
        Retrieves Posts from the last 7 days matching a search query.
        Args:
            query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length.
            start_time: YYYY-MM-DDTHH:mm:ssZ. The oldest UTC timestamp from which the Posts will be provided. Timestamp is in second granularity and is inclusive (i.e. 12:00:01 includes the first second of the minute).
            end_time: YYYY-MM-DDTHH:mm:ssZ. The newest, most recent UTC timestamp to which the Posts will be provided. Timestamp is in second granularity and is exclusive (i.e. 12:00:01 excludes the first second of the minute).
            since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID.
            until_id: Returns results with a Post ID less than (that is, older than) the specified ID.
            max_results: The maximum number of search results to be returned by a request.
            next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified.
            pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified.
            sort_order: This order in which to return results.
            tweet_fields: A comma separated list of Tweet fields to display.
            expansions: A comma separated list of fields to expand.
            media_fields: A comma separated list of Media fields to display.
            poll_fields: A comma separated list of Poll fields to display.
            user_fields: A comma separated list of User fields to display.
            place_fields: A comma separated list of Place fields to display.
            Yields:
            SearchRecentResponse: One page of results at a time. Automatically handles pagination using next_token.
        Note:
            This method automatically paginates through all results. To get just the first page,
            you can call it once and break, or use the pagination_token parameter to start at a specific page.
        """
        url = self.client.base_url + "/2/tweets/search/recent"
        # Priority: bearer_token > access_token (matches TypeScript behavior)
        if self.client.bearer_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.bearer_token}"
            )
        elif self.client.access_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
        # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
        # Priority: access_token > oauth2_session (for token refresh support)
        if self.client.access_token:
            # Use access_token directly as bearer token (matches TypeScript)
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
            # If we have oauth2_auth, check if token needs refresh
            if self.client.oauth2_auth and self.client.token:
                if self.client.is_token_expired():
                    self.client.refresh_token()
                    # Update access_token after refresh
                    if self.client.access_token:
                        self.client.session.headers["Authorization"] = (
                            f"Bearer {self.client.access_token}"
                        )
        elif self.client.oauth2_auth and self.client.token:
            # Fallback: use oauth2_session if available (for backward compatibility)
            # Check if token needs refresh
            if self.client.is_token_expired():
                self.client.refresh_token()
        headers = {}
        # Prepare request data
        json_data = None
        # Determine pagination parameter name
        pagination_param_name = "pagination_token"
        # Start with provided pagination_token, or None for first page
        # Check if pagination_token parameter exists in the method signature
        current_pagination_token = pagination_token
        while True:
            # Build query parameters for this page
            page_params = {}
            if query is not None:
                page_params["query"] = query
            if start_time is not None:
                page_params["start_time"] = start_time
            if end_time is not None:
                page_params["end_time"] = end_time
            if since_id is not None:
                page_params["since_id"] = since_id
            if until_id is not None:
                page_params["until_id"] = until_id
            if max_results is not None:
                page_params["max_results"] = max_results
            if sort_order is not None:
                page_params["sort_order"] = sort_order
            if tweet_fields is not None:
                page_params["tweet.fields"] = ",".join(
                    str(item) for item in tweet_fields
                )
            if expansions is not None:
                page_params["expansions"] = ",".join(str(item) for item in expansions)
            if media_fields is not None:
                page_params["media.fields"] = ",".join(
                    str(item) for item in media_fields
                )
            if poll_fields is not None:
                page_params["poll.fields"] = ",".join(str(item) for item in poll_fields)
            if user_fields is not None:
                page_params["user.fields"] = ",".join(str(item) for item in user_fields)
            if place_fields is not None:
                page_params["place.fields"] = ",".join(
                    str(item) for item in place_fields
                )
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Make the request
            response = self.client.session.get(
                url,
                params=page_params,
                headers=headers,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = SearchRecentResponse.model_validate(response_data)
            # Yield this page
            yield page_response
            # Extract next_token from response
            next_token = None
            try:
                # Try response.meta.next_token (most common pattern)
                if hasattr(page_response, "meta") and page_response.meta is not None:
                    meta = page_response.meta
                    # If meta is a Pydantic model, try to dump it
                    if hasattr(meta, "model_dump"):
                        try:
                            meta_dict = meta.model_dump()
                            next_token = meta_dict.get("next_token")
                        except (AttributeError, TypeError):
                            pass
                    # Otherwise try attribute access
                    if not next_token and hasattr(meta, "next_token"):
                        next_token = getattr(meta, "next_token", None)
                    # If meta is a dict, access it directly
                    if not next_token and isinstance(meta, dict):
                        next_token = meta.get("next_token")
            except (AttributeError, TypeError):
                pass
            # Try dict access if we have a dict
            if not next_token and isinstance(response_data, dict):
                try:
                    meta = response_data.get("meta")
                    if meta and isinstance(meta, dict):
                        next_token = meta.get("next_token")
                except (AttributeError, TypeError, KeyError):
                    pass
            # If no next_token, we're done
            if not next_token:
                break
            # Update token for next iteration
            current_pagination_token = next_token

            # Optional: Add rate limit backoff here if needed
            # time.sleep(0.1)  # Small delay to avoid rate limits


    def get_quoted(
        self,
        id: Any,
        max_results: int = None,
        pagination_token: Any = None,
        exclude: List = None,
        tweet_fields: List = None,
        expansions: List = None,
        media_fields: List = None,
        poll_fields: List = None,
        user_fields: List = None,
        place_fields: List = None,
    ) -> Iterator[GetQuotedResponse]:
        """
        Get Quoted Posts
        Retrieves a list of Posts that quote a specific Post by its ID.
        Args:
            id: A single Post ID.
            max_results: The maximum number of results to be returned.
            pagination_token: This parameter is used to get a specified 'page' of results.
            exclude: The set of entities to exclude (e.g. 'replies' or 'retweets').
            tweet_fields: A comma separated list of Tweet fields to display.
            expansions: A comma separated list of fields to expand.
            media_fields: A comma separated list of Media fields to display.
            poll_fields: A comma separated list of Poll fields to display.
            user_fields: A comma separated list of User fields to display.
            place_fields: A comma separated list of Place fields to display.
            Yields:
            GetQuotedResponse: One page of results at a time. Automatically handles pagination using next_token.
        Note:
            This method automatically paginates through all results. To get just the first page,
            you can call it once and break, or use the pagination_token parameter to start at a specific page.
        """
        url = self.client.base_url + "/2/tweets/{id}/quote_tweets"
        url = url.replace("{id}", str(id))
        # Priority: bearer_token > access_token (matches TypeScript behavior)
        if self.client.bearer_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.bearer_token}"
            )
        elif self.client.access_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
        # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
        # Priority: access_token > oauth2_session (for token refresh support)
        if self.client.access_token:
            # Use access_token directly as bearer token (matches TypeScript)
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
            # If we have oauth2_auth, check if token needs refresh
            if self.client.oauth2_auth and self.client.token:
                if self.client.is_token_expired():
                    self.client.refresh_token()
                    # Update access_token after refresh
                    if self.client.access_token:
                        self.client.session.headers["Authorization"] = (
                            f"Bearer {self.client.access_token}"
                        )
        elif self.client.oauth2_auth and self.client.token:
            # Fallback: use oauth2_session if available (for backward compatibility)
            # Check if token needs refresh
            if self.client.is_token_expired():
                self.client.refresh_token()
        headers = {}
        # Prepare request data
        json_data = None
        # Determine pagination parameter name
        pagination_param_name = "pagination_token"
        # Start with provided pagination_token, or None for first page
        # Check if pagination_token parameter exists in the method signature
        current_pagination_token = pagination_token
        while True:
            # Build query parameters for this page
            page_params = {}
            if max_results is not None:
                page_params["max_results"] = max_results
            if exclude is not None:
                page_params["exclude"] = ",".join(str(item) for item in exclude)
            if tweet_fields is not None:
                page_params["tweet.fields"] = ",".join(
                    str(item) for item in tweet_fields
                )
            if expansions is not None:
                page_params["expansions"] = ",".join(str(item) for item in expansions)
            if media_fields is not None:
                page_params["media.fields"] = ",".join(
                    str(item) for item in media_fields
                )
            if poll_fields is not None:
                page_params["poll.fields"] = ",".join(str(item) for item in poll_fields)
            if user_fields is not None:
                page_params["user.fields"] = ",".join(str(item) for item in user_fields)
            if place_fields is not None:
                page_params["place.fields"] = ",".join(
                    str(item) for item in place_fields
                )
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Make the request
            response = self.client.session.get(
                url,
                params=page_params,
                headers=headers,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = GetQuotedResponse.model_validate(response_data)
            # Yield this page
            yield page_response
            # Extract next_token from response
            next_token = None
            try:
                # Try response.meta.next_token (most common pattern)
                if hasattr(page_response, "meta") and page_response.meta is not None:
                    meta = page_response.meta
                    # If meta is a Pydantic model, try to dump it
                    if hasattr(meta, "model_dump"):
                        try:
                            meta_dict = meta.model_dump()
                            next_token = meta_dict.get("next_token")
                        except (AttributeError, TypeError):
                            pass
                    # Otherwise try attribute access
                    if not next_token and hasattr(meta, "next_token"):
                        next_token = getattr(meta, "next_token", None)
                    # If meta is a dict, access it directly
                    if not next_token and isinstance(meta, dict):
                        next_token = meta.get("next_token")
            except (AttributeError, TypeError):
                pass
            # Try dict access if we have a dict
            if not next_token and isinstance(response_data, dict):
                try:
                    meta = response_data.get("meta")
                    if meta and isinstance(meta, dict):
                        next_token = meta.get("next_token")
                except (AttributeError, TypeError, KeyError):
                    pass
            # If no next_token, we're done
            if not next_token:
                break
            # Update token for next iteration
            current_pagination_token = next_token

            # Optional: Add rate limit backoff here if needed
            # time.sleep(0.1)  # Small delay to avoid rate limits


    def hide_reply(
        self, tweet_id: Any, body: Optional[HideReplyRequest] = None
    ) -> HideReplyResponse:
        """
        Hide reply
        Hides or unhides a reply to a conversation owned by the authenticated user.
        Args:
            tweet_id: The ID of the reply that you want to hide or unhide.
            body: Request body
        Returns:
            HideReplyResponse: Response data
        """
        url = self.client.base_url + "/2/tweets/{tweet_id}/hidden"
        url = url.replace("{tweet_id}", str(tweet_id))
        # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
        # Priority: access_token > oauth2_session (for token refresh support)
        if self.client.access_token:
            # Use access_token directly as bearer token (matches TypeScript)
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
            # If we have oauth2_auth, check if token needs refresh
            if self.client.oauth2_auth and self.client.token:
                if self.client.is_token_expired():
                    self.client.refresh_token()
                    # Update access_token after refresh
                    if self.client.access_token:
                        self.client.session.headers["Authorization"] = (
                            f"Bearer {self.client.access_token}"
                        )
        elif self.client.oauth2_auth and self.client.token:
            # Fallback: use oauth2_session if available (for backward compatibility)
            # Check if token needs refresh
            if self.client.is_token_expired():
                self.client.refresh_token()
        headers = {}
        headers["Content-Type"] = "application/json"
        # Prepare request data
        json_data = None
        if body is not None:
            json_data = (
                body.model_dump(exclude_none=True)
                if hasattr(body, "model_dump")
                else body
            )
        # Determine pagination parameter name
        pagination_param_name = "pagination_token"  # Default fallback
        # Start with provided pagination_token, or None for first page
        # Check if pagination_token parameter exists in the method signature
        current_pagination_token = None
        while True:
            # Build query parameters for this page
            page_params = {}
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Make the request
            # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
            response = self.client.session.put(
                url,
                params=page_params,
                headers=headers,
                json=json_data,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = HideReplyResponse.model_validate(response_data)
            # Yield this page
            yield page_response
            # Extract next_token from response
            next_token = None
            try:
                # Try response.meta.next_token (most common pattern)
                if hasattr(page_response, "meta") and page_response.meta is not None:
                    meta = page_response.meta
                    # If meta is a Pydantic model, try to dump it
                    if hasattr(meta, "model_dump"):
                        try:
                            meta_dict = meta.model_dump()
                            next_token = meta_dict.get("next_token")
                        except (AttributeError, TypeError):
                            pass
                    # Otherwise try attribute access
                    if not next_token and hasattr(meta, "next_token"):
                        next_token = getattr(meta, "next_token", None)
                    # If meta is a dict, access it directly
                    if not next_token and isinstance(meta, dict):
                        next_token = meta.get("next_token")
            except (AttributeError, TypeError):
                pass
            # Try dict access if we have a dict
            if not next_token and isinstance(response_data, dict):
                try:
                    meta = response_data.get("meta")
                    if meta and isinstance(meta, dict):
                        next_token = meta.get("next_token")
                except (AttributeError, TypeError, KeyError):
                    pass
            # If no next_token, we're done
            if not next_token:
                break
            # Update token for next iteration
            current_pagination_token = next_token

            # Optional: Add rate limit backoff here if needed
            # time.sleep(0.1)  # Small delay to avoid rate limits


    def get_by_ids(
        self,
        ids: List,
        tweet_fields: List = None,
        expansions: List = None,
        media_fields: List = None,
        poll_fields: List = None,
        user_fields: List = None,
        place_fields: List = None,
    ) -> GetByIdsResponse:
        """
        Get Posts by IDs
        Retrieves details of multiple Posts by their IDs.
        Args:
            ids: A comma separated list of Post IDs. Up to 100 are allowed in a single request.
            tweet_fields: A comma separated list of Tweet fields to display.
            expansions: A comma separated list of fields to expand.
            media_fields: A comma separated list of Media fields to display.
            poll_fields: A comma separated list of Poll fields to display.
            user_fields: A comma separated list of User fields to display.
            place_fields: A comma separated list of Place fields to display.
            Returns:
            GetByIdsResponse: Response data
        """
        url = self.client.base_url + "/2/tweets"
        # Priority: bearer_token > access_token (matches TypeScript behavior)
        if self.client.bearer_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.bearer_token}"
            )
        elif self.client.access_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
        # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
        # Priority: access_token > oauth2_session (for token refresh support)
        if self.client.access_token:
            # Use access_token directly as bearer token (matches TypeScript)
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
            # If we have oauth2_auth, check if token needs refresh
            if self.client.oauth2_auth and self.client.token:
                if self.client.is_token_expired():
                    self.client.refresh_token()
                    # Update access_token after refresh
                    if self.client.access_token:
                        self.client.session.headers["Authorization"] = (
                            f"Bearer {self.client.access_token}"
                        )
        elif self.client.oauth2_auth and self.client.token:
            # Fallback: use oauth2_session if available (for backward compatibility)
            # Check if token needs refresh
            if self.client.is_token_expired():
                self.client.refresh_token()
        headers = {}
        # Prepare request data
        json_data = None
        # Determine pagination parameter name
        pagination_param_name = "pagination_token"  # Default fallback
        # Start with provided pagination_token, or None for first page
        # Check if pagination_token parameter exists in the method signature
        current_pagination_token = None
        while True:
            # Build query parameters for this page
            page_params = {}
            if ids is not None:
                page_params["ids"] = ",".join(str(item) for item in ids)
            if tweet_fields is not None:
                page_params["tweet.fields"] = ",".join(
                    str(item) for item in tweet_fields
                )
            if expansions is not None:
                page_params["expansions"] = ",".join(str(item) for item in expansions)
            if media_fields is not None:
                page_params["media.fields"] = ",".join(
                    str(item) for item in media_fields
                )
            if poll_fields is not None:
                page_params["poll.fields"] = ",".join(str(item) for item in poll_fields)
            if user_fields is not None:
                page_params["user.fields"] = ",".join(str(item) for item in user_fields)
            if place_fields is not None:
                page_params["place.fields"] = ",".join(
                    str(item) for item in place_fields
                )
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Make the request
            response = self.client.session.get(
                url,
                params=page_params,
                headers=headers,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = GetByIdsResponse.model_validate(response_data)
            # Yield this page
            yield page_response
            # Extract next_token from response
            next_token = None
            try:
                # Try response.meta.next_token (most common pattern)
                if hasattr(page_response, "meta") and page_response.meta is not None:
                    meta = page_response.meta
                    # If meta is a Pydantic model, try to dump it
                    if hasattr(meta, "model_dump"):
                        try:
                            meta_dict = meta.model_dump()
                            next_token = meta_dict.get("next_token")
                        except (AttributeError, TypeError):
                            pass
                    # Otherwise try attribute access
                    if not next_token and hasattr(meta, "next_token"):
                        next_token = getattr(meta, "next_token", None)
                    # If meta is a dict, access it directly
                    if not next_token and isinstance(meta, dict):
                        next_token = meta.get("next_token")
            except (AttributeError, TypeError):
                pass
            # Try dict access if we have a dict
            if not next_token and isinstance(response_data, dict):
                try:
                    meta = response_data.get("meta")
                    if meta and isinstance(meta, dict):
                        next_token = meta.get("next_token")
                except (AttributeError, TypeError, KeyError):
                    pass
            # If no next_token, we're done
            if not next_token:
                break
            # Update token for next iteration
            current_pagination_token = next_token

            # Optional: Add rate limit backoff here if needed
            # time.sleep(0.1)  # Small delay to avoid rate limits


    def create(self, body: CreateRequest) -> Dict[str, Any]:
        """
        Create or Edit Post
        Creates a new Post for the authenticated user, or edits an existing Post when edit_options are provided.
        body: Request body
        Returns:
            CreateResponse: Response data
        """
        url = self.client.base_url + "/2/tweets"
        # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
        # Priority: access_token > oauth2_session (for token refresh support)
        if self.client.access_token:
            # Use access_token directly as bearer token (matches TypeScript)
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
            # If we have oauth2_auth, check if token needs refresh
            if self.client.oauth2_auth and self.client.token:
                if self.client.is_token_expired():
                    self.client.refresh_token()
                    # Update access_token after refresh
                    if self.client.access_token:
                        self.client.session.headers["Authorization"] = (
                            f"Bearer {self.client.access_token}"
                        )
        elif self.client.oauth2_auth and self.client.token:
            # Fallback: use oauth2_session if available (for backward compatibility)
            # Check if token needs refresh
            if self.client.is_token_expired():
                self.client.refresh_token()
        headers = {}
        headers["Content-Type"] = "application/json"
        # Prepare request data
        json_data = None
        if body is not None:
            json_data = (
                body.model_dump(exclude_none=True)
                if hasattr(body, "model_dump")
                else body
            )
        # Determine pagination parameter name
        pagination_param_name = "pagination_token"  # Default fallback
        # Start with provided pagination_token, or None for first page
        # Check if pagination_token parameter exists in the method signature
        current_pagination_token = None
        while True:
            # Build query parameters for this page
            page_params = {}
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Make the request
            # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
            response = self.client.session.post(
                url,
                params=page_params,
                headers=headers,
                json=json_data,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = CreateResponse.model_validate(response_data)
            # Yield this page
            yield page_response
            # Extract next_token from response
            next_token = None
            try:
                # Try response.meta.next_token (most common pattern)
                if hasattr(page_response, "meta") and page_response.meta is not None:
                    meta = page_response.meta
                    # If meta is a Pydantic model, try to dump it
                    if hasattr(meta, "model_dump"):
                        try:
                            meta_dict = meta.model_dump()
                            next_token = meta_dict.get("next_token")
                        except (AttributeError, TypeError):
                            pass
                    # Otherwise try attribute access
                    if not next_token and hasattr(meta, "next_token"):
                        next_token = getattr(meta, "next_token", None)
                    # If meta is a dict, access it directly
                    if not next_token and isinstance(meta, dict):
                        next_token = meta.get("next_token")
            except (AttributeError, TypeError):
                pass
            # Try dict access if we have a dict
            if not next_token and isinstance(response_data, dict):
                try:
                    meta = response_data.get("meta")
                    if meta and isinstance(meta, dict):
                        next_token = meta.get("next_token")
                except (AttributeError, TypeError, KeyError):
                    pass
            # If no next_token, we're done
            if not next_token:
                break
            # Update token for next iteration
            current_pagination_token = next_token

            # Optional: Add rate limit backoff here if needed
            # time.sleep(0.1)  # Small delay to avoid rate limits


    def get_insights_historical(
        self,
        tweet_ids: List,
        end_time: str,
        start_time: str,
        granularity: str,
        requested_metrics: List,
        engagement_fields: List = None,
    ) -> GetInsightsHistoricalResponse:
        """
        Get historical Post insights
        Retrieves historical engagement metrics for specified Posts within a defined time range.
        Args:
            tweet_ids: List of PostIds for historical metrics.
            end_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range.
            start_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range.
            granularity: granularity of metrics response.
            requested_metrics: request metrics for historical request.
            engagement_fields: A comma separated list of Engagement fields to display.
            Returns:
            GetInsightsHistoricalResponse: Response data
        """
        url = self.client.base_url + "/2/insights/historical"
        # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
        # Priority: access_token > oauth2_session (for token refresh support)
        if self.client.access_token:
            # Use access_token directly as bearer token (matches TypeScript)
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
            # If we have oauth2_auth, check if token needs refresh
            if self.client.oauth2_auth and self.client.token:
                if self.client.is_token_expired():
                    self.client.refresh_token()
                    # Update access_token after refresh
                    if self.client.access_token:
                        self.client.session.headers["Authorization"] = (
                            f"Bearer {self.client.access_token}"
                        )
        elif self.client.oauth2_auth and self.client.token:
            # Fallback: use oauth2_session if available (for backward compatibility)
            # Check if token needs refresh
            if self.client.is_token_expired():
                self.client.refresh_token()
        headers = {}
        # Prepare request data
        json_data = None
        # Determine pagination parameter name
        pagination_param_name = "pagination_token"  # Default fallback
        # Start with provided pagination_token, or None for first page
        # Check if pagination_token parameter exists in the method signature
        current_pagination_token = None
        while True:
            # Build query parameters for this page
            page_params = {}
            if tweet_ids is not None:
                page_params["tweet_ids"] = ",".join(str(item) for item in tweet_ids)
            if end_time is not None:
                page_params["end_time"] = end_time
            if start_time is not None:
                page_params["start_time"] = start_time
            if granularity is not None:
                page_params["granularity"] = granularity
            if requested_metrics is not None:
                page_params["requested_metrics"] = ",".join(
                    str(item) for item in requested_metrics
                )
            if engagement_fields is not None:
                page_params["engagement.fields"] = ",".join(
                    str(item) for item in engagement_fields
                )
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Make the request
            # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
            response = self.client.session.get(
                url,
                params=page_params,
                headers=headers,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = GetInsightsHistoricalResponse.model_validate(response_data)
            # Yield this page
            yield page_response
            # Extract next_token from response
            next_token = None
            try:
                # Try response.meta.next_token (most common pattern)
                if hasattr(page_response, "meta") and page_response.meta is not None:
                    meta = page_response.meta
                    # If meta is a Pydantic model, try to dump it
                    if hasattr(meta, "model_dump"):
                        try:
                            meta_dict = meta.model_dump()
                            next_token = meta_dict.get("next_token")
                        except (AttributeError, TypeError):
                            pass
                    # Otherwise try attribute access
                    if not next_token and hasattr(meta, "next_token"):
                        next_token = getattr(meta, "next_token", None)
                    # If meta is a dict, access it directly
                    if not next_token and isinstance(meta, dict):
                        next_token = meta.get("next_token")
            except (AttributeError, TypeError):
                pass
            # Try dict access if we have a dict
            if not next_token and isinstance(response_data, dict):
                try:
                    meta = response_data.get("meta")
                    if meta and isinstance(meta, dict):
                        next_token = meta.get("next_token")
                except (AttributeError, TypeError, KeyError):
                    pass
            # If no next_token, we're done
            if not next_token:
                break
            # Update token for next iteration
            current_pagination_token = next_token

            # Optional: Add rate limit backoff here if needed
            # time.sleep(0.1)  # Small delay to avoid rate limits


    def get_counts_recent(
        self,
        query: str,
        start_time: str = None,
        end_time: str = None,
        since_id: Any = None,
        until_id: Any = None,
        next_token: Any = None,
        pagination_token: Any = None,
        granularity: str = None,
        search_count_fields: List = None,
    ) -> Iterator[GetCountsRecentResponse]:
        """
        Get count of recent Posts
        Retrieves the count of Posts from the last 7 days matching a search query.
        Args:
            query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length.
            start_time: YYYY-MM-DDTHH:mm:ssZ. The oldest UTC timestamp (from most recent 7 days) from which the Posts will be provided. Timestamp is in second granularity and is inclusive (i.e. 12:00:01 includes the first second of the minute).
            end_time: YYYY-MM-DDTHH:mm:ssZ. The newest, most recent UTC timestamp to which the Posts will be provided. Timestamp is in second granularity and is exclusive (i.e. 12:00:01 excludes the first second of the minute).
            since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID.
            until_id: Returns results with a Post ID less than (that is, older than) the specified ID.
            next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified.
            pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified.
            granularity: The granularity for the search counts results.
            search_count_fields: A comma separated list of SearchCount fields to display.
            Yields:
            GetCountsRecentResponse: One page of results at a time. Automatically handles pagination using next_token.
        Note:
            This method automatically paginates through all results. To get just the first page,
            you can call it once and break, or use the pagination_token parameter to start at a specific page.
        """
        url = self.client.base_url + "/2/tweets/counts/recent"
        # Priority: bearer_token > access_token (matches TypeScript behavior)
        if self.client.bearer_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.bearer_token}"
            )
        elif self.client.access_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
        headers = {}
        # Prepare request data
        json_data = None
        # Determine pagination parameter name
        pagination_param_name = "pagination_token"
        # Start with provided pagination_token, or None for first page
        # Check if pagination_token parameter exists in the method signature
        current_pagination_token = pagination_token
        while True:
            # Build query parameters for this page
            page_params = {}
            if query is not None:
                page_params["query"] = query
            if start_time is not None:
                page_params["start_time"] = start_time
            if end_time is not None:
                page_params["end_time"] = end_time
            if since_id is not None:
                page_params["since_id"] = since_id
            if until_id is not None:
                page_params["until_id"] = until_id
            if granularity is not None:
                page_params["granularity"] = granularity
            if search_count_fields is not None:
                page_params["search_count.fields"] = ",".join(
                    str(item) for item in search_count_fields
                )
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Make the request
            response = self.client.session.get(
                url,
                params=page_params,
                headers=headers,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = GetCountsRecentResponse.model_validate(response_data)
            # Yield this page
            yield page_response
            # Extract next_token from response
            next_token = None
            try:
                # Try response.meta.next_token (most common pattern)
                if hasattr(page_response, "meta") and page_response.meta is not None:
                    meta = page_response.meta
                    # If meta is a Pydantic model, try to dump it
                    if hasattr(meta, "model_dump"):
                        try:
                            meta_dict = meta.model_dump()
                            next_token = meta_dict.get("next_token")
                        except (AttributeError, TypeError):
                            pass
                    # Otherwise try attribute access
                    if not next_token and hasattr(meta, "next_token"):
                        next_token = getattr(meta, "next_token", None)
                    # If meta is a dict, access it directly
                    if not next_token and isinstance(meta, dict):
                        next_token = meta.get("next_token")
            except (AttributeError, TypeError):
                pass
            # Try dict access if we have a dict
            if not next_token and isinstance(response_data, dict):
                try:
                    meta = response_data.get("meta")
                    if meta and isinstance(meta, dict):
                        next_token = meta.get("next_token")
                except (AttributeError, TypeError, KeyError):
                    pass
            # If no next_token, we're done
            if not next_token:
                break
            # Update token for next iteration
            current_pagination_token = next_token

            # Optional: Add rate limit backoff here if needed
            # time.sleep(0.1)  # Small delay to avoid rate limits


    def get_reposted_by(
        self,
        id: Any,
        max_results: int = None,
        pagination_token: Any = None,
        user_fields: List = None,
        expansions: List = None,
        tweet_fields: List = None,
    ) -> Iterator[GetRepostedByResponse]:
        """
        Get Reposted by
        Retrieves a list of Users who reposted a specific Post by its ID.
        Args:
            id: A single Post ID.
            max_results: The maximum number of results.
            pagination_token: This parameter is used to get the next 'page' of results.
            user_fields: A comma separated list of User fields to display.
            expansions: A comma separated list of fields to expand.
            tweet_fields: A comma separated list of Tweet fields to display.
            Yields:
            GetRepostedByResponse: One page of results at a time. Automatically handles pagination using next_token.
        Note:
            This method automatically paginates through all results. To get just the first page,
            you can call it once and break, or use the pagination_token parameter to start at a specific page.
        """
        url = self.client.base_url + "/2/tweets/{id}/retweeted_by"
        url = url.replace("{id}", str(id))
        # Priority: bearer_token > access_token (matches TypeScript behavior)
        if self.client.bearer_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.bearer_token}"
            )
        elif self.client.access_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
        # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
        # Priority: access_token > oauth2_session (for token refresh support)
        if self.client.access_token:
            # Use access_token directly as bearer token (matches TypeScript)
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
            # If we have oauth2_auth, check if token needs refresh
            if self.client.oauth2_auth and self.client.token:
                if self.client.is_token_expired():
                    self.client.refresh_token()
                    # Update access_token after refresh
                    if self.client.access_token:
                        self.client.session.headers["Authorization"] = (
                            f"Bearer {self.client.access_token}"
                        )
        elif self.client.oauth2_auth and self.client.token:
            # Fallback: use oauth2_session if available (for backward compatibility)
            # Check if token needs refresh
            if self.client.is_token_expired():
                self.client.refresh_token()
        headers = {}
        # Prepare request data
        json_data = None
        # Determine pagination parameter name
        pagination_param_name = "pagination_token"
        # Start with provided pagination_token, or None for first page
        # Check if pagination_token parameter exists in the method signature
        current_pagination_token = pagination_token
        while True:
            # Build query parameters for this page
            page_params = {}
            if max_results is not None:
                page_params["max_results"] = max_results
            if user_fields is not None:
                page_params["user.fields"] = ",".join(str(item) for item in user_fields)
            if expansions is not None:
                page_params["expansions"] = ",".join(str(item) for item in expansions)
            if tweet_fields is not None:
                page_params["tweet.fields"] = ",".join(
                    str(item) for item in tweet_fields
                )
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Make the request
            response = self.client.session.get(
                url,
                params=page_params,
                headers=headers,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = GetRepostedByResponse.model_validate(response_data)
            # Yield this page
            yield page_response
            # Extract next_token from response
            next_token = None
            try:
                # Try response.meta.next_token (most common pattern)
                if hasattr(page_response, "meta") and page_response.meta is not None:
                    meta = page_response.meta
                    # If meta is a Pydantic model, try to dump it
                    if hasattr(meta, "model_dump"):
                        try:
                            meta_dict = meta.model_dump()
                            next_token = meta_dict.get("next_token")
                        except (AttributeError, TypeError):
                            pass
                    # Otherwise try attribute access
                    if not next_token and hasattr(meta, "next_token"):
                        next_token = getattr(meta, "next_token", None)
                    # If meta is a dict, access it directly
                    if not next_token and isinstance(meta, dict):
                        next_token = meta.get("next_token")
            except (AttributeError, TypeError):
                pass
            # Try dict access if we have a dict
            if not next_token and isinstance(response_data, dict):
                try:
                    meta = response_data.get("meta")
                    if meta and isinstance(meta, dict):
                        next_token = meta.get("next_token")
                except (AttributeError, TypeError, KeyError):
                    pass
            # If no next_token, we're done
            if not next_token:
                break
            # Update token for next iteration
            current_pagination_token = next_token

            # Optional: Add rate limit backoff here if needed
            # time.sleep(0.1)  # Small delay to avoid rate limits


    def get_analytics(
        self,
        ids: List,
        end_time: str,
        start_time: str,
        granularity: str,
        analytics_fields: List = None,
    ) -> GetAnalyticsResponse:
        """
        Get Post analytics
        Retrieves analytics data for specified Posts within a defined time range.
        Args:
            ids: A comma separated list of Post IDs. Up to 100 are allowed in a single request.
            end_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range.
            start_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range.
            granularity: The granularity for the search counts results.
            analytics_fields: A comma separated list of Analytics fields to display.
            Returns:
            GetAnalyticsResponse: Response data
        """
        url = self.client.base_url + "/2/tweets/analytics"
        # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
        # Priority: access_token > oauth2_session (for token refresh support)
        if self.client.access_token:
            # Use access_token directly as bearer token (matches TypeScript)
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
            # If we have oauth2_auth, check if token needs refresh
            if self.client.oauth2_auth and self.client.token:
                if self.client.is_token_expired():
                    self.client.refresh_token()
                    # Update access_token after refresh
                    if self.client.access_token:
                        self.client.session.headers["Authorization"] = (
                            f"Bearer {self.client.access_token}"
                        )
        elif self.client.oauth2_auth and self.client.token:
            # Fallback: use oauth2_session if available (for backward compatibility)
            # Check if token needs refresh
            if self.client.is_token_expired():
                self.client.refresh_token()
        headers = {}
        # Prepare request data
        json_data = None
        # Determine pagination parameter name
        pagination_param_name = "pagination_token"  # Default fallback
        # Start with provided pagination_token, or None for first page
        # Check if pagination_token parameter exists in the method signature
        current_pagination_token = None
        while True:
            # Build query parameters for this page
            page_params = {}
            if ids is not None:
                page_params["ids"] = ",".join(str(item) for item in ids)
            if end_time is not None:
                page_params["end_time"] = end_time
            if start_time is not None:
                page_params["start_time"] = start_time
            if granularity is not None:
                page_params["granularity"] = granularity
            if analytics_fields is not None:
                page_params["analytics.fields"] = ",".join(
                    str(item) for item in analytics_fields
                )
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Make the request
            # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
            response = self.client.session.get(
                url,
                params=page_params,
                headers=headers,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = GetAnalyticsResponse.model_validate(response_data)
            # Yield this page
            yield page_response
            # Extract next_token from response
            next_token = None
            try:
                # Try response.meta.next_token (most common pattern)
                if hasattr(page_response, "meta") and page_response.meta is not None:
                    meta = page_response.meta
                    # If meta is a Pydantic model, try to dump it
                    if hasattr(meta, "model_dump"):
                        try:
                            meta_dict = meta.model_dump()
                            next_token = meta_dict.get("next_token")
                        except (AttributeError, TypeError):
                            pass
                    # Otherwise try attribute access
                    if not next_token and hasattr(meta, "next_token"):
                        next_token = getattr(meta, "next_token", None)
                    # If meta is a dict, access it directly
                    if not next_token and isinstance(meta, dict):
                        next_token = meta.get("next_token")
            except (AttributeError, TypeError):
                pass
            # Try dict access if we have a dict
            if not next_token and isinstance(response_data, dict):
                try:
                    meta = response_data.get("meta")
                    if meta and isinstance(meta, dict):
                        next_token = meta.get("next_token")
                except (AttributeError, TypeError, KeyError):
                    pass
            # If no next_token, we're done
            if not next_token:
                break
            # Update token for next iteration
            current_pagination_token = next_token

            # Optional: Add rate limit backoff here if needed
            # time.sleep(0.1)  # Small delay to avoid rate limits


    def get_counts_all(
        self,
        query: str,
        start_time: str = None,
        end_time: str = None,
        since_id: Any = None,
        until_id: Any = None,
        next_token: Any = None,
        pagination_token: Any = None,
        granularity: str = None,
        search_count_fields: List = None,
    ) -> Iterator[GetCountsAllResponse]:
        """
        Get count of all Posts
        Retrieves the count of Posts matching a search query from the full archive.
        Args:
            query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length.
            start_time: YYYY-MM-DDTHH:mm:ssZ. The oldest UTC timestamp (from most recent 7 days) from which the Posts will be provided. Timestamp is in second granularity and is inclusive (i.e. 12:00:01 includes the first second of the minute).
            end_time: YYYY-MM-DDTHH:mm:ssZ. The newest, most recent UTC timestamp to which the Posts will be provided. Timestamp is in second granularity and is exclusive (i.e. 12:00:01 excludes the first second of the minute).
            since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID.
            until_id: Returns results with a Post ID less than (that is, older than) the specified ID.
            next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified.
            pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified.
            granularity: The granularity for the search counts results.
            search_count_fields: A comma separated list of SearchCount fields to display.
            Yields:
            GetCountsAllResponse: One page of results at a time. Automatically handles pagination using next_token.
        Note:
            This method automatically paginates through all results. To get just the first page,
            you can call it once and break, or use the pagination_token parameter to start at a specific page.
        """
        url = self.client.base_url + "/2/tweets/counts/all"
        # Priority: bearer_token > access_token (matches TypeScript behavior)
        if self.client.bearer_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.bearer_token}"
            )
        elif self.client.access_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
        headers = {}
        # Prepare request data
        json_data = None
        # Determine pagination parameter name
        pagination_param_name = "pagination_token"
        # Start with provided pagination_token, or None for first page
        # Check if pagination_token parameter exists in the method signature
        current_pagination_token = pagination_token
        while True:
            # Build query parameters for this page
            page_params = {}
            if query is not None:
                page_params["query"] = query
            if start_time is not None:
                page_params["start_time"] = start_time
            if end_time is not None:
                page_params["end_time"] = end_time
            if since_id is not None:
                page_params["since_id"] = since_id
            if until_id is not None:
                page_params["until_id"] = until_id
            if granularity is not None:
                page_params["granularity"] = granularity
            if search_count_fields is not None:
                page_params["search_count.fields"] = ",".join(
                    str(item) for item in search_count_fields
                )
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Make the request
            response = self.client.session.get(
                url,
                params=page_params,
                headers=headers,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = GetCountsAllResponse.model_validate(response_data)
            # Yield this page
            yield page_response
            # Extract next_token from response
            next_token = None
            try:
                # Try response.meta.next_token (most common pattern)
                if hasattr(page_response, "meta") and page_response.meta is not None:
                    meta = page_response.meta
                    # If meta is a Pydantic model, try to dump it
                    if hasattr(meta, "model_dump"):
                        try:
                            meta_dict = meta.model_dump()
                            next_token = meta_dict.get("next_token")
                        except (AttributeError, TypeError):
                            pass
                    # Otherwise try attribute access
                    if not next_token and hasattr(meta, "next_token"):
                        next_token = getattr(meta, "next_token", None)
                    # If meta is a dict, access it directly
                    if not next_token and isinstance(meta, dict):
                        next_token = meta.get("next_token")
            except (AttributeError, TypeError):
                pass
            # Try dict access if we have a dict
            if not next_token and isinstance(response_data, dict):
                try:
                    meta = response_data.get("meta")
                    if meta and isinstance(meta, dict):
                        next_token = meta.get("next_token")
                except (AttributeError, TypeError, KeyError):
                    pass
            # If no next_token, we're done
            if not next_token:
                break
            # Update token for next iteration
            current_pagination_token = next_token

            # Optional: Add rate limit backoff here if needed
            # time.sleep(0.1)  # Small delay to avoid rate limits


    def search_all(
        self,
        query: str,
        start_time: str = None,
        end_time: str = None,
        since_id: Any = None,
        until_id: Any = None,
        max_results: int = None,
        next_token: Any = None,
        pagination_token: Any = None,
        sort_order: str = None,
        tweet_fields: List = None,
        expansions: List = None,
        media_fields: List = None,
        poll_fields: List = None,
        user_fields: List = None,
        place_fields: List = None,
    ) -> Iterator[SearchAllResponse]:
        """
        Search all Posts
        Retrieves Posts from the full archive matching a search query.
        Args:
            query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length.
            start_time: YYYY-MM-DDTHH:mm:ssZ. The oldest UTC timestamp from which the Posts will be provided. Timestamp is in second granularity and is inclusive (i.e. 12:00:01 includes the first second of the minute).
            end_time: YYYY-MM-DDTHH:mm:ssZ. The newest, most recent UTC timestamp to which the Posts will be provided. Timestamp is in second granularity and is exclusive (i.e. 12:00:01 excludes the first second of the minute).
            since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID.
            until_id: Returns results with a Post ID less than (that is, older than) the specified ID.
            max_results: The maximum number of search results to be returned by a request.
            next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified.
            pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified.
            sort_order: This order in which to return results.
            tweet_fields: A comma separated list of Tweet fields to display.
            expansions: A comma separated list of fields to expand.
            media_fields: A comma separated list of Media fields to display.
            poll_fields: A comma separated list of Poll fields to display.
            user_fields: A comma separated list of User fields to display.
            place_fields: A comma separated list of Place fields to display.
            Yields:
            SearchAllResponse: One page of results at a time. Automatically handles pagination using next_token.
        Note:
            This method automatically paginates through all results. To get just the first page,
            you can call it once and break, or use the pagination_token parameter to start at a specific page.
        """
        url = self.client.base_url + "/2/tweets/search/all"
        # Priority: bearer_token > access_token (matches TypeScript behavior)
        if self.client.bearer_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.bearer_token}"
            )
        elif self.client.access_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
        headers = {}
        # Prepare request data
        json_data = None
        # Determine pagination parameter name
        pagination_param_name = "pagination_token"
        # Start with provided pagination_token, or None for first page
        # Check if pagination_token parameter exists in the method signature
        current_pagination_token = pagination_token
        while True:
            # Build query parameters for this page
            page_params = {}
            if query is not None:
                page_params["query"] = query
            if start_time is not None:
                page_params["start_time"] = start_time
            if end_time is not None:
                page_params["end_time"] = end_time
            if since_id is not None:
                page_params["since_id"] = since_id
            if until_id is not None:
                page_params["until_id"] = until_id
            if max_results is not None:
                page_params["max_results"] = max_results
            if sort_order is not None:
                page_params["sort_order"] = sort_order
            if tweet_fields is not None:
                page_params["tweet.fields"] = ",".join(
                    str(item) for item in tweet_fields
                )
            if expansions is not None:
                page_params["expansions"] = ",".join(str(item) for item in expansions)
            if media_fields is not None:
                page_params["media.fields"] = ",".join(
                    str(item) for item in media_fields
                )
            if poll_fields is not None:
                page_params["poll.fields"] = ",".join(str(item) for item in poll_fields)
            if user_fields is not None:
                page_params["user.fields"] = ",".join(str(item) for item in user_fields)
            if place_fields is not None:
                page_params["place.fields"] = ",".join(
                    str(item) for item in place_fields
                )
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Make the request
            response = self.client.session.get(
                url,
                params=page_params,
                headers=headers,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = SearchAllResponse.model_validate(response_data)
            # Yield this page
            yield page_response
            # Extract next_token from response
            next_token = None
            try:
                # Try response.meta.next_token (most common pattern)
                if hasattr(page_response, "meta") and page_response.meta is not None:
                    meta = page_response.meta
                    # If meta is a Pydantic model, try to dump it
                    if hasattr(meta, "model_dump"):
                        try:
                            meta_dict = meta.model_dump()
                            next_token = meta_dict.get("next_token")
                        except (AttributeError, TypeError):
                            pass
                    # Otherwise try attribute access
                    if not next_token and hasattr(meta, "next_token"):
                        next_token = getattr(meta, "next_token", None)
                    # If meta is a dict, access it directly
                    if not next_token and isinstance(meta, dict):
                        next_token = meta.get("next_token")
            except (AttributeError, TypeError):
                pass
            # Try dict access if we have a dict
            if not next_token and isinstance(response_data, dict):
                try:
                    meta = response_data.get("meta")
                    if meta and isinstance(meta, dict):
                        next_token = meta.get("next_token")
                except (AttributeError, TypeError, KeyError):
                    pass
            # If no next_token, we're done
            if not next_token:
                break
            # Update token for next iteration
            current_pagination_token = next_token

            # Optional: Add rate limit backoff here if needed
            # time.sleep(0.1)  # Small delay to avoid rate limits


    def get_by_id(
        self,
        id: Any,
        tweet_fields: List = None,
        expansions: List = None,
        media_fields: List = None,
        poll_fields: List = None,
        user_fields: List = None,
        place_fields: List = None,
    ) -> GetByIdResponse:
        """
        Get Post by ID
        Retrieves details of a specific Post by its ID.
        Args:
            id: A single Post ID.
            tweet_fields: A comma separated list of Tweet fields to display.
            expansions: A comma separated list of fields to expand.
            media_fields: A comma separated list of Media fields to display.
            poll_fields: A comma separated list of Poll fields to display.
            user_fields: A comma separated list of User fields to display.
            place_fields: A comma separated list of Place fields to display.
            Returns:
            GetByIdResponse: Response data
        """
        url = self.client.base_url + "/2/tweets/{id}"
        url = url.replace("{id}", str(id))
        # Priority: bearer_token > access_token (matches TypeScript behavior)
        if self.client.bearer_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.bearer_token}"
            )
        elif self.client.access_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
        # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
        # Priority: access_token > oauth2_session (for token refresh support)
        if self.client.access_token:
            # Use access_token directly as bearer token (matches TypeScript)
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
            # If we have oauth2_auth, check if token needs refresh
            if self.client.oauth2_auth and self.client.token:
                if self.client.is_token_expired():
                    self.client.refresh_token()
                    # Update access_token after refresh
                    if self.client.access_token:
                        self.client.session.headers["Authorization"] = (
                            f"Bearer {self.client.access_token}"
                        )
        elif self.client.oauth2_auth and self.client.token:
            # Fallback: use oauth2_session if available (for backward compatibility)
            # Check if token needs refresh
            if self.client.is_token_expired():
                self.client.refresh_token()
        headers = {}
        # Prepare request data
        json_data = None
        # Determine pagination parameter name
        pagination_param_name = "pagination_token"  # Default fallback
        # Start with provided pagination_token, or None for first page
        # Check if pagination_token parameter exists in the method signature
        current_pagination_token = None
        while True:
            # Build query parameters for this page
            page_params = {}
            if tweet_fields is not None:
                page_params["tweet.fields"] = ",".join(
                    str(item) for item in tweet_fields
                )
            if expansions is not None:
                page_params["expansions"] = ",".join(str(item) for item in expansions)
            if media_fields is not None:
                page_params["media.fields"] = ",".join(
                    str(item) for item in media_fields
                )
            if poll_fields is not None:
                page_params["poll.fields"] = ",".join(str(item) for item in poll_fields)
            if user_fields is not None:
                page_params["user.fields"] = ",".join(str(item) for item in user_fields)
            if place_fields is not None:
                page_params["place.fields"] = ",".join(
                    str(item) for item in place_fields
                )
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Make the request
            response = self.client.session.get(
                url,
                params=page_params,
                headers=headers,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = GetByIdResponse.model_validate(response_data)
            # Yield this page
            yield page_response
            # Extract next_token from response
            next_token = None
            try:
                # Try response.meta.next_token (most common pattern)
                if hasattr(page_response, "meta") and page_response.meta is not None:
                    meta = page_response.meta
                    # If meta is a Pydantic model, try to dump it
                    if hasattr(meta, "model_dump"):
                        try:
                            meta_dict = meta.model_dump()
                            next_token = meta_dict.get("next_token")
                        except (AttributeError, TypeError):
                            pass
                    # Otherwise try attribute access
                    if not next_token and hasattr(meta, "next_token"):
                        next_token = getattr(meta, "next_token", None)
                    # If meta is a dict, access it directly
                    if not next_token and isinstance(meta, dict):
                        next_token = meta.get("next_token")
            except (AttributeError, TypeError):
                pass
            # Try dict access if we have a dict
            if not next_token and isinstance(response_data, dict):
                try:
                    meta = response_data.get("meta")
                    if meta and isinstance(meta, dict):
                        next_token = meta.get("next_token")
                except (AttributeError, TypeError, KeyError):
                    pass
            # If no next_token, we're done
            if not next_token:
                break
            # Update token for next iteration
            current_pagination_token = next_token

            # Optional: Add rate limit backoff here if needed
            # time.sleep(0.1)  # Small delay to avoid rate limits


    def delete(self, id: Any) -> DeleteResponse:
        """
        Delete Post
        Deletes a specific Post by its ID, if owned by the authenticated user.
        Args:
            id: The ID of the Post to be deleted.
            Returns:
            DeleteResponse: Response data
        """
        url = self.client.base_url + "/2/tweets/{id}"
        url = url.replace("{id}", str(id))
        # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
        # Priority: access_token > oauth2_session (for token refresh support)
        if self.client.access_token:
            # Use access_token directly as bearer token (matches TypeScript)
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
            # If we have oauth2_auth, check if token needs refresh
            if self.client.oauth2_auth and self.client.token:
                if self.client.is_token_expired():
                    self.client.refresh_token()
                    # Update access_token after refresh
                    if self.client.access_token:
                        self.client.session.headers["Authorization"] = (
                            f"Bearer {self.client.access_token}"
                        )
        elif self.client.oauth2_auth and self.client.token:
            # Fallback: use oauth2_session if available (for backward compatibility)
            # Check if token needs refresh
            if self.client.is_token_expired():
                self.client.refresh_token()
        headers = {}
        # Prepare request data
        json_data = None
        # Determine pagination parameter name
        pagination_param_name = "pagination_token"  # Default fallback
        # Start with provided pagination_token, or None for first page
        # Check if pagination_token parameter exists in the method signature
        current_pagination_token = None
        while True:
            # Build query parameters for this page
            page_params = {}
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Make the request
            # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
            response = self.client.session.delete(
                url,
                params=page_params,
                headers=headers,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = DeleteResponse.model_validate(response_data)
            # Yield this page
            yield page_response
            # Extract next_token from response
            next_token = None
            try:
                # Try response.meta.next_token (most common pattern)
                if hasattr(page_response, "meta") and page_response.meta is not None:
                    meta = page_response.meta
                    # If meta is a Pydantic model, try to dump it
                    if hasattr(meta, "model_dump"):
                        try:
                            meta_dict = meta.model_dump()
                            next_token = meta_dict.get("next_token")
                        except (AttributeError, TypeError):
                            pass
                    # Otherwise try attribute access
                    if not next_token and hasattr(meta, "next_token"):
                        next_token = getattr(meta, "next_token", None)
                    # If meta is a dict, access it directly
                    if not next_token and isinstance(meta, dict):
                        next_token = meta.get("next_token")
            except (AttributeError, TypeError):
                pass
            # Try dict access if we have a dict
            if not next_token and isinstance(response_data, dict):
                try:
                    meta = response_data.get("meta")
                    if meta and isinstance(meta, dict):
                        next_token = meta.get("next_token")
                except (AttributeError, TypeError, KeyError):
                    pass
            # If no next_token, we're done
            if not next_token:
                break
            # Update token for next iteration
            current_pagination_token = next_token

            # Optional: Add rate limit backoff here if needed
            # time.sleep(0.1)  # Small delay to avoid rate limits


    def get_reposts(
        self,
        id: Any,
        max_results: int = None,
        pagination_token: Any = None,
        tweet_fields: List = None,
        expansions: List = None,
        media_fields: List = None,
        poll_fields: List = None,
        user_fields: List = None,
        place_fields: List = None,
    ) -> Iterator[GetRepostsResponse]:
        """
        Get Reposts
        Retrieves a list of Posts that repost a specific Post by its ID.
        Args:
            id: A single Post ID.
            max_results: The maximum number of results.
            pagination_token: This parameter is used to get the next 'page' of results.
            tweet_fields: A comma separated list of Tweet fields to display.
            expansions: A comma separated list of fields to expand.
            media_fields: A comma separated list of Media fields to display.
            poll_fields: A comma separated list of Poll fields to display.
            user_fields: A comma separated list of User fields to display.
            place_fields: A comma separated list of Place fields to display.
            Yields:
            GetRepostsResponse: One page of results at a time. Automatically handles pagination using next_token.
        Note:
            This method automatically paginates through all results. To get just the first page,
            you can call it once and break, or use the pagination_token parameter to start at a specific page.
        """
        url = self.client.base_url + "/2/tweets/{id}/retweets"
        url = url.replace("{id}", str(id))
        # Priority: bearer_token > access_token (matches TypeScript behavior)
        if self.client.bearer_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.bearer_token}"
            )
        elif self.client.access_token:
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
        # OAuth2UserToken: Use access_token as bearer token (matches TypeScript behavior)
        # Priority: access_token > oauth2_session (for token refresh support)
        if self.client.access_token:
            # Use access_token directly as bearer token (matches TypeScript)
            self.client.session.headers["Authorization"] = (
                f"Bearer {self.client.access_token}"
            )
            # If we have oauth2_auth, check if token needs refresh
            if self.client.oauth2_auth and self.client.token:
                if self.client.is_token_expired():
                    self.client.refresh_token()
                    # Update access_token after refresh
                    if self.client.access_token:
                        self.client.session.headers["Authorization"] = (
                            f"Bearer {self.client.access_token}"
                        )
        elif self.client.oauth2_auth and self.client.token:
            # Fallback: use oauth2_session if available (for backward compatibility)
            # Check if token needs refresh
            if self.client.is_token_expired():
                self.client.refresh_token()
        headers = {}
        # Prepare request data
        json_data = None
        # Determine pagination parameter name
        pagination_param_name = "pagination_token"
        # Start with provided pagination_token, or None for first page
        # Check if pagination_token parameter exists in the method signature
        current_pagination_token = pagination_token
        while True:
            # Build query parameters for this page
            page_params = {}
            if max_results is not None:
                page_params["max_results"] = max_results
            if tweet_fields is not None:
                page_params["tweet.fields"] = ",".join(
                    str(item) for item in tweet_fields
                )
            if expansions is not None:
                page_params["expansions"] = ",".join(str(item) for item in expansions)
            if media_fields is not None:
                page_params["media.fields"] = ",".join(
                    str(item) for item in media_fields
                )
            if poll_fields is not None:
                page_params["poll.fields"] = ",".join(str(item) for item in poll_fields)
            if user_fields is not None:
                page_params["user.fields"] = ",".join(str(item) for item in user_fields)
            if place_fields is not None:
                page_params["place.fields"] = ",".join(
                    str(item) for item in place_fields
                )
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Make the request
            response = self.client.session.get(
                url,
                params=page_params,
                headers=headers,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = GetRepostsResponse.model_validate(response_data)
            # Yield this page
            yield page_response
            # Extract next_token from response
            next_token = None
            try:
                # Try response.meta.next_token (most common pattern)
                if hasattr(page_response, "meta") and page_response.meta is not None:
                    meta = page_response.meta
                    # If meta is a Pydantic model, try to dump it
                    if hasattr(meta, "model_dump"):
                        try:
                            meta_dict = meta.model_dump()
                            next_token = meta_dict.get("next_token")
                        except (AttributeError, TypeError):
                            pass
                    # Otherwise try attribute access
                    if not next_token and hasattr(meta, "next_token"):
                        next_token = getattr(meta, "next_token", None)
                    # If meta is a dict, access it directly
                    if not next_token and isinstance(meta, dict):
                        next_token = meta.get("next_token")
            except (AttributeError, TypeError):
                pass
            # Try dict access if we have a dict
            if not next_token and isinstance(response_data, dict):
                try:
                    meta = response_data.get("meta")
                    if meta and isinstance(meta, dict):
                        next_token = meta.get("next_token")
                except (AttributeError, TypeError, KeyError):
                    pass
            # If no next_token, we're done
            if not next_token:
                break
            # Update token for next iteration
            current_pagination_token = next_token

            # Optional: Add rate limit backoff here if needed
            # time.sleep(0.1)  # Small delay to avoid rate limits
