# 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 communities client for the X API.

This module provides a client for interacting with the communities 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
import urllib.parse


if TYPE_CHECKING:
    from ..client import Client
from .models import (
    GetByIdResponse,
    SearchResponse,
)


class CommunitiesClient:
    """Client for communities operations"""


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


    def get_by_id(self, id: Any, community_fields: List = None) -> GetByIdResponse:
        """
        Get Community by ID
        Retrieves details of a specific Community by its ID.
        Args:
            id: The ID of the Community.
            community_fields: A comma separated list of Community fields to display.
            Returns:
            GetByIdResponse: Response data
        """
        url = self.client.base_url + "/2/communities/{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()
        # UserToken: OAuth1.0a authentication - header will be built dynamically in request
        # OAuth1 header must be built per-request with method, URL, and body
        # This is handled in the request logic below
        params = {}
        if community_fields is not None:
            params["community.fields"] = ",".join(
                str(item) for item in community_fields
            )
        headers = {}
        # Prepare request data
        json_data = None
        # Select authentication method based on endpoint requirements and available credentials
        # Priority strategy (matches TypeScript):
        # 1. If endpoint only accepts one method, use that (if available)
        # 2. If endpoint accepts multiple methods:
        #    - For write operations (POST/PUT/DELETE/PATCH): Prefer OAuth1 > OAuth2 User Token > Bearer Token
        #    - For read operations (GET): Prefer Bearer Token > OAuth2 User Token > OAuth1
        # 3. If no security requirements: Bearer Token > OAuth2 User Token > OAuth1
        selected_auth = None
        # Check what auth methods we have available
        available_bearer = bool(self.client.bearer_token)
        available_oauth2 = bool(self.client.access_token)
        available_oauth1 = bool(self.client.auth and self.client.auth.access_token)
        # Count acceptable schemes
        acceptable_schemes = []
        acceptable_schemes.append("BearerToken")
        acceptable_schemes.append("OAuth2UserToken")
        acceptable_schemes.append("UserToken")
        # If only one scheme is acceptable, use it if available
        if len(acceptable_schemes) == 1:
            scheme = acceptable_schemes[0]
            if scheme == "BearerToken" and available_bearer:
                selected_auth = "bearer_token"
            elif scheme == "OAuth2UserToken" and available_oauth2:
                selected_auth = "oauth2_user_context"
            elif scheme == "UserToken" and available_oauth1:
                selected_auth = "oauth1"
        # Multiple schemes acceptable - use priority based on operation type
        elif len(acceptable_schemes) > 1:
            is_write_operation = "get" in ["POST", "PUT", "DELETE", "PATCH"]
            if is_write_operation:
                # Priority for write operations: OAuth1 > OAuth2 User Token > Bearer Token
                if "UserToken" in acceptable_schemes and available_oauth1:
                    selected_auth = "oauth1"
                elif "OAuth2UserToken" in acceptable_schemes and available_oauth2:
                    selected_auth = "oauth2_user_context"
                elif "BearerToken" in acceptable_schemes and available_bearer:
                    selected_auth = "bearer_token"
            else:
                # Priority for read operations: Bearer Token > OAuth2 User Token > OAuth1
                if "BearerToken" in acceptable_schemes and available_bearer:
                    selected_auth = "bearer_token"
                elif "OAuth2UserToken" in acceptable_schemes and available_oauth2:
                    selected_auth = "oauth2_user_context"
                elif "UserToken" in acceptable_schemes and available_oauth1:
                    selected_auth = "oauth1"
        # Apply selected authentication
        if selected_auth == "oauth1":
            # OAuth1 authentication - build proper OAuth1 header dynamically
            # Build OAuth1 header with method, URL, and body
            # For OAuth1, we need to include query params in the URL for signature
            full_url = url
            if params:
                query_string = urllib.parse.urlencode(params)
                full_url = f"{url}?{query_string}" if query_string else url
            # Prepare body for OAuth1 signature (form-encoded, not JSON)
            body_string = ""
            # Build OAuth1 authorization header
            oauth_header = self.client.auth.build_request_header(
                method="get", url=full_url, body=body_string
            )
            headers["Authorization"] = oauth_header
        elif selected_auth == "bearer_token":
            # Bearer token authentication
            if self.client.bearer_token:
                headers["Authorization"] = f"Bearer {self.client.bearer_token}"
            elif self.client.access_token:
                headers["Authorization"] = f"Bearer {self.client.access_token}"
        elif selected_auth == "oauth2_user_context":
            # OAuth2 User Token authentication
            if self.client.access_token:
                headers["Authorization"] = f"Bearer {self.client.access_token}"
                # Check if token needs refresh
                if self.client.oauth2_auth and self.client.token:
                    if self.client.is_token_expired():
                        self.client.refresh_token()
                        if self.client.access_token:
                            headers["Authorization"] = (
                                f"Bearer {self.client.access_token}"
                            )
        # Make the request
        if not selected_auth:
            # No suitable auth method found - validate authentication
            required_schemes = (
                acceptable_schemes if "acceptable_schemes" in locals() else []
            )
            if required_schemes:
                available = []
                if available_bearer and "BearerToken" in required_schemes:
                    available.append("BearerToken")
                if available_oauth2 and "OAuth2UserToken" in required_schemes:
                    available.append("OAuth2UserToken")
                if available_oauth1 and "UserToken" in required_schemes:
                    available.append("UserToken")
                if not available:
                    raise ValueError(
                        f"Authentication required for this endpoint. Required schemes: {required_schemes}. Available: {[s for s in required_schemes if (s == 'BearerToken' and available_bearer) or (s == 'OAuth2UserToken' and available_oauth2) or (s == 'UserToken' and available_oauth1)]}"
                    )
        response = self.client.session.get(
            url,
            params=params,
            headers=headers,
        )
        # Check for errors
        response.raise_for_status()
        # Parse the response data
        response_data = response.json()
        # Convert to Pydantic model if applicable
        return GetByIdResponse.model_validate(response_data)


    def search(
        self,
        query: str,
        max_results: int = None,
        next_token: Any = None,
        pagination_token: Any = None,
        community_fields: List = None,
    ) -> Iterator[SearchResponse]:
        """
        Search Communities
        Retrieves a list of Communities matching the specified search query.
        Args:
            query: Query to search communities.
            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.
            community_fields: A comma separated list of Community fields to display.
            Yields:
            SearchResponse: 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/communities/search"
        # 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()
        # UserToken: OAuth1.0a authentication - header will be built dynamically in request
        # OAuth1 header must be built per-request with method, URL, and body
        # This is handled in the request logic below
        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 max_results is not None:
                page_params["max_results"] = max_results
            if community_fields is not None:
                page_params["community.fields"] = ",".join(
                    str(item) for item in community_fields
                )
            # Add pagination token for this page
            if current_pagination_token:
                page_params[pagination_param_name] = current_pagination_token
            # Select authentication method (same logic as regular_request)
            # Priority strategy (matches TypeScript):
            # 1. If endpoint only accepts one method, use that (if available)
            # 2. If endpoint accepts multiple methods:
            #    - For write operations (POST/PUT/DELETE/PATCH): Prefer OAuth1 > OAuth2 User Token > Bearer Token
            #    - For read operations (GET): Prefer Bearer Token > OAuth2 User Token > OAuth1
            # 3. If no security requirements: Bearer Token > OAuth2 User Token > OAuth1
            page_selected_auth = None
            # Check what auth methods we have available
            page_available_bearer = bool(self.client.bearer_token)
            page_available_oauth2 = bool(self.client.access_token)
            page_available_oauth1 = bool(
                self.client.auth and self.client.auth.access_token
            )
            # Count acceptable schemes
            page_acceptable_schemes = []
            page_acceptable_schemes.append("OAuth2UserToken")
            page_acceptable_schemes.append("UserToken")
            # If only one scheme is acceptable, use it if available
            if len(page_acceptable_schemes) == 1:
                scheme = page_acceptable_schemes[0]
                if scheme == "BearerToken" and page_available_bearer:
                    page_selected_auth = "bearer_token"
                elif scheme == "OAuth2UserToken" and page_available_oauth2:
                    page_selected_auth = "oauth2_user_context"
                elif scheme == "UserToken" and page_available_oauth1:
                    page_selected_auth = "oauth1"
            # Multiple schemes acceptable - use priority based on operation type
            elif len(page_acceptable_schemes) > 1:
                is_write_operation = "get" in ["POST", "PUT", "DELETE", "PATCH"]
                if is_write_operation:
                    # Priority for write operations: OAuth1 > OAuth2 User Token > Bearer Token
                    if "UserToken" in page_acceptable_schemes and page_available_oauth1:
                        page_selected_auth = "oauth1"
                    elif (
                        "OAuth2UserToken" in page_acceptable_schemes
                        and page_available_oauth2
                    ):
                        page_selected_auth = "oauth2_user_context"
                    elif (
                        "BearerToken" in page_acceptable_schemes
                        and page_available_bearer
                    ):
                        page_selected_auth = "bearer_token"
                else:
                    # Priority for read operations: Bearer Token > OAuth2 User Token > OAuth1
                    if (
                        "BearerToken" in page_acceptable_schemes
                        and page_available_bearer
                    ):
                        page_selected_auth = "bearer_token"
                    elif (
                        "OAuth2UserToken" in page_acceptable_schemes
                        and page_available_oauth2
                    ):
                        page_selected_auth = "oauth2_user_context"
                    elif (
                        "UserToken" in page_acceptable_schemes and page_available_oauth1
                    ):
                        page_selected_auth = "oauth1"
            # Apply selected authentication for this page
            page_headers = headers.copy()
            if page_selected_auth == "oauth1":
                # OAuth1 authentication - build proper OAuth1 header dynamically
                # Build OAuth1 header with method, URL, and body
                # For OAuth1, we need to include query params in the URL for signature
                full_url = url
                if page_params:
                    query_string = urllib.parse.urlencode(page_params)
                    full_url = f"{url}?{query_string}" if query_string else url
                # Prepare body for OAuth1 signature (form-encoded, not JSON)
                body_string = ""
                # Build OAuth1 authorization header
                oauth_header = self.client.auth.build_request_header(
                    method="get", url=full_url, body=body_string
                )
                page_headers["Authorization"] = oauth_header
            elif page_selected_auth == "bearer_token":
                # Bearer token authentication
                if self.client.bearer_token:
                    page_headers["Authorization"] = f"Bearer {self.client.bearer_token}"
                elif self.client.access_token:
                    page_headers["Authorization"] = f"Bearer {self.client.access_token}"
            elif page_selected_auth == "oauth2_user_context":
                # OAuth2 User Token authentication
                if self.client.access_token:
                    page_headers["Authorization"] = f"Bearer {self.client.access_token}"
                    # Check if token needs refresh
                    if self.client.oauth2_auth and self.client.token:
                        if self.client.is_token_expired():
                            self.client.refresh_token()
                            if self.client.access_token:
                                page_headers["Authorization"] = (
                                    f"Bearer {self.client.access_token}"
                                )
            # Make the request
            if not page_selected_auth:
                # No suitable auth method found - validate authentication
                required_schemes = (
                    page_acceptable_schemes
                    if "page_acceptable_schemes" in locals()
                    else []
                )
                if required_schemes:
                    available = []
                    if page_available_bearer and "BearerToken" in required_schemes:
                        available.append("BearerToken")
                    if page_available_oauth2 and "OAuth2UserToken" in required_schemes:
                        available.append("OAuth2UserToken")
                    if page_available_oauth1 and "UserToken" in required_schemes:
                        available.append("UserToken")
                    if not available:
                        raise ValueError(
                            f"Authentication required for this endpoint. Required schemes: {required_schemes}. Available: {[s for s in required_schemes if (s == 'BearerToken' and page_available_bearer) or (s == 'OAuth2UserToken' and page_available_oauth2) or (s == 'UserToken' and page_available_oauth1)]}"
                        )
            response = self.client.session.get(
                url,
                params=page_params,
                headers=page_headers,
            )
            # Check for errors
            response.raise_for_status()
            # Parse the response data
            response_data = response.json()
            # Convert to Pydantic model if applicable
            page_response = SearchResponse.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
