/*
 * Zernio API
 *
 * API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api
 *
 * The version of the OpenAPI document: 1.0.4
 * Contact: support@zernio.com
 * Generated by: https://openapi-generator.tech
 */

use super::{configuration, ContentType, Error};
use crate::{apis::ResponseContent, models};
use reqwest;
use serde::{de::Error as _, Deserialize, Serialize};

/// struct for typed errors of method [`get_analytics`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetAnalyticsError {
    Status400(models::GetAnalytics400Response),
    Status401(models::InlineObject),
    Status402(models::GetAnalytics402Response),
    Status404(models::InlineObject1),
    Status424(models::AnalyticsSinglePostResponse),
    Status500(models::ErrorResponse),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_best_time_to_post`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetBestTimeToPostError {
    Status401(models::InlineObject),
    Status403(models::GetBestTimeToPost403Response),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_content_decay`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetContentDecayError {
    Status401(models::InlineObject),
    Status403(models::GetBestTimeToPost403Response),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_daily_metrics`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetDailyMetricsError {
    Status401(models::InlineObject),
    Status402(models::GetAnalytics402Response),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_facebook_page_insights`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetFacebookPageInsightsError {
    Status400(),
    Status401(models::InlineObject),
    Status402(),
    Status404(),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_facebook_post_reactions`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetFacebookPostReactionsError {
    Status400(),
    Status401(models::InlineObject),
    Status404(),
    Status502(),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_follower_stats`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetFollowerStatsError {
    Status401(models::InlineObject),
    Status403(models::GetFollowerStats403Response),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_google_business_performance`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetGoogleBusinessPerformanceError {
    Status400(models::GetGoogleBusinessPerformance400Response),
    Status401(models::InlineObject),
    Status402(models::GetAnalytics402Response),
    Status403(models::GetYouTubeDailyViews403Response),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_google_business_search_keywords`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetGoogleBusinessSearchKeywordsError {
    Status400(models::GetGoogleBusinessSearchKeywords400Response),
    Status401(models::InlineObject),
    Status402(models::GetAnalytics402Response),
    Status403(models::GetYouTubeDailyViews403Response),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_instagram_account_insights`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetInstagramAccountInsightsError {
    Status400(models::GetYouTubeDailyViews400Response),
    Status401(models::InlineObject),
    Status402(models::GetAnalytics402Response),
    Status403(models::GetYouTubeDailyViews403Response),
    Status404(models::GetInstagramAccountInsights404Response),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_instagram_demographics`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetInstagramDemographicsError {
    Status400(models::GetYouTubeDailyViews400Response),
    Status401(models::InlineObject),
    Status402(models::GetAnalytics402Response),
    Status403(models::GetYouTubeDailyViews403Response),
    Status404(models::GetInstagramAccountInsights404Response),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_instagram_follower_history`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetInstagramFollowerHistoryError {
    Status400(),
    Status401(models::InlineObject),
    Status402(),
    Status404(),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_linked_in_aggregate_analytics`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetLinkedInAggregateAnalyticsError {
    Status400(models::GetLinkedInAggregateAnalytics400Response),
    Status401(models::InlineObject),
    Status402(models::GetLinkedInAggregateAnalytics402Response),
    Status403(models::GetLinkedInAggregateAnalytics403Response),
    Status404(),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_linked_in_org_aggregate_analytics`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetLinkedInOrgAggregateAnalyticsError {
    Status400(),
    Status401(models::InlineObject),
    Status402(),
    Status403(),
    Status404(),
    Status412(),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_linked_in_post_analytics`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetLinkedInPostAnalyticsError {
    Status400(models::GetLinkedInPostAnalytics400Response),
    Status401(models::InlineObject),
    Status402(),
    Status403(models::GetLinkedInPostAnalytics403Response),
    Status404(models::GetLinkedInAggregateAnalytics402Response),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_linked_in_post_reactions`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetLinkedInPostReactionsError {
    Status400(models::GetLinkedInPostReactions400Response),
    Status401(models::InlineObject),
    Status402(),
    Status403(),
    Status404(),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_post_timeline`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetPostTimelineError {
    Status400(models::GetPostTimeline400Response),
    Status401(models::InlineObject),
    Status402(models::GetAnalytics402Response),
    Status403(models::GetPostTimeline403Response),
    Status404(models::GetPostTimeline404Response),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_posting_frequency`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetPostingFrequencyError {
    Status401(models::InlineObject),
    Status403(models::GetBestTimeToPost403Response),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_tik_tok_account_insights`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetTikTokAccountInsightsError {
    Status400(),
    Status401(models::InlineObject),
    Status402(),
    Status404(),
    Status412(),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_you_tube_channel_insights`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetYouTubeChannelInsightsError {
    Status400(),
    Status401(models::InlineObject),
    Status402(),
    Status404(),
    Status412(models::YouTubeScopeMissingResponse),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_you_tube_daily_views`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetYouTubeDailyViewsError {
    Status400(models::GetYouTubeDailyViews400Response),
    Status401(models::InlineObject),
    Status402(models::GetAnalytics402Response),
    Status403(models::GetYouTubeDailyViews403Response),
    Status412(models::YouTubeScopeMissingResponse),
    Status500(models::GetYouTubeDailyViews500Response),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_you_tube_demographics`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetYouTubeDemographicsError {
    Status400(models::GetYouTubeDailyViews400Response),
    Status401(models::InlineObject),
    Status402(models::GetAnalytics402Response),
    Status403(models::GetYouTubeDailyViews403Response),
    Status404(models::GetInstagramAccountInsights404Response),
    Status412(models::GetYouTubeDemographics412Response),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_you_tube_video_retention`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetYouTubeVideoRetentionError {
    Status400(models::GetYouTubeDailyViews400Response),
    Status401(models::InlineObject),
    Status402(models::GetAnalytics402Response),
    Status403(models::GetYouTubeDailyViews403Response),
    Status404(models::GetYouTubeVideoRetention404Response),
    Status412(models::YouTubeScopeMissingResponse),
    Status500(models::GetYouTubeDailyViews500Response),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`sync_external_posts`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum SyncExternalPostsError {
    Status400(models::ErrorResponse),
    Status404(models::ErrorResponse),
    UnknownValue(serde_json::Value),
}

/// Returns analytics for posts. With postId, returns a single post. Without it, returns a paginated list with overview stats. Accepts both Zernio Post IDs and External Post IDs (auto-resolved). fromDate defaults to 90 days ago if omitted, max range 366 days. Single post lookups may return 202 (sync pending) or 424 (all platforms failed). For follower stats, use /v1/accounts/follower-stats.  LinkedIn personal accounts: Analytics are only available for posts published through Zernio. LinkedIn's API only returns metrics for posts authored by the authenticated user. Organization/company page analytics work for all posts.
pub async fn get_analytics(
    configuration: &configuration::Configuration,
    post_id: Option<&str>,
    platform: Option<&str>,
    profile_id: Option<&str>,
    account_id: Option<&str>,
    source: Option<&str>,
    from_date: Option<String>,
    to_date: Option<String>,
    limit: Option<i32>,
    page: Option<i32>,
    sort_by: Option<&str>,
    order: Option<&str>,
) -> Result<models::GetAnalytics200Response, Error<GetAnalyticsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_post_id = post_id;
    let p_query_platform = platform;
    let p_query_profile_id = profile_id;
    let p_query_account_id = account_id;
    let p_query_source = source;
    let p_query_from_date = from_date;
    let p_query_to_date = to_date;
    let p_query_limit = limit;
    let p_query_page = page;
    let p_query_sort_by = sort_by;
    let p_query_order = order;

    let uri_str = format!("{}/v1/analytics", configuration.base_path);
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    if let Some(ref param_value) = p_query_post_id {
        req_builder = req_builder.query(&[("postId", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_platform {
        req_builder = req_builder.query(&[("platform", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_profile_id {
        req_builder = req_builder.query(&[("profileId", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_account_id {
        req_builder = req_builder.query(&[("accountId", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_source {
        req_builder = req_builder.query(&[("source", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_from_date {
        req_builder = req_builder.query(&[("fromDate", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_to_date {
        req_builder = req_builder.query(&[("toDate", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_limit {
        req_builder = req_builder.query(&[("limit", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_page {
        req_builder = req_builder.query(&[("page", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_sort_by {
        req_builder = req_builder.query(&[("sortBy", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_order {
        req_builder = req_builder.query(&[("order", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetAnalytics200Response`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GetAnalytics200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetAnalyticsError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns the best times to post based on historical engagement data. Groups all published posts by day of week and hour (UTC), calculating average engagement per slot. Use this to auto-schedule posts at optimal times. Requires the Analytics add-on.
pub async fn get_best_time_to_post(
    configuration: &configuration::Configuration,
    platform: Option<&str>,
    profile_id: Option<&str>,
    account_id: Option<&str>,
    source: Option<&str>,
) -> Result<models::GetBestTimeToPost200Response, Error<GetBestTimeToPostError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_platform = platform;
    let p_query_profile_id = profile_id;
    let p_query_account_id = account_id;
    let p_query_source = source;

    let uri_str = format!("{}/v1/analytics/best-time", configuration.base_path);
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    if let Some(ref param_value) = p_query_platform {
        req_builder = req_builder.query(&[("platform", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_profile_id {
        req_builder = req_builder.query(&[("profileId", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_account_id {
        req_builder = req_builder.query(&[("accountId", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_source {
        req_builder = req_builder.query(&[("source", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetBestTimeToPost200Response`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GetBestTimeToPost200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetBestTimeToPostError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns how engagement accumulates over time after a post is published. Each bucket shows what percentage of the post's total engagement had been reached by that time window. Useful for understanding content lifespan (e.g. \"posts reach 78% of total engagement within 24 hours\"). Requires the Analytics add-on.
pub async fn get_content_decay(
    configuration: &configuration::Configuration,
    platform: Option<&str>,
    profile_id: Option<&str>,
    account_id: Option<&str>,
    source: Option<&str>,
) -> Result<models::GetContentDecay200Response, Error<GetContentDecayError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_platform = platform;
    let p_query_profile_id = profile_id;
    let p_query_account_id = account_id;
    let p_query_source = source;

    let uri_str = format!("{}/v1/analytics/content-decay", configuration.base_path);
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    if let Some(ref param_value) = p_query_platform {
        req_builder = req_builder.query(&[("platform", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_profile_id {
        req_builder = req_builder.query(&[("profileId", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_account_id {
        req_builder = req_builder.query(&[("accountId", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_source {
        req_builder = req_builder.query(&[("source", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetContentDecay200Response`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GetContentDecay200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetContentDecayError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns daily aggregated analytics metrics and a per-platform breakdown. Each day includes post count, platform distribution, and summed metrics (impressions, reach, likes, comments, shares, saves, clicks, views). Defaults to the last 180 days. Requires the Analytics add-on.
pub async fn get_daily_metrics(
    configuration: &configuration::Configuration,
    platform: Option<&str>,
    profile_id: Option<&str>,
    account_id: Option<&str>,
    from_date: Option<String>,
    to_date: Option<String>,
    source: Option<&str>,
    attribution: Option<&str>,
) -> Result<models::GetDailyMetrics200Response, Error<GetDailyMetricsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_platform = platform;
    let p_query_profile_id = profile_id;
    let p_query_account_id = account_id;
    let p_query_from_date = from_date;
    let p_query_to_date = to_date;
    let p_query_source = source;
    let p_query_attribution = attribution;

    let uri_str = format!("{}/v1/analytics/daily-metrics", configuration.base_path);
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    if let Some(ref param_value) = p_query_platform {
        req_builder = req_builder.query(&[("platform", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_profile_id {
        req_builder = req_builder.query(&[("profileId", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_account_id {
        req_builder = req_builder.query(&[("accountId", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_from_date {
        req_builder = req_builder.query(&[("fromDate", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_to_date {
        req_builder = req_builder.query(&[("toDate", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_source {
        req_builder = req_builder.query(&[("source", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_attribution {
        req_builder = req_builder.query(&[("attribution", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetDailyMetrics200Response`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GetDailyMetrics200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetDailyMetricsError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns page-level Facebook insights (media views, views, post engagements, video metrics, follower counts). Response shape matches /v1/analytics/instagram/account-insights so the same client handling works across platforms.  Metric names track the current (post-November 2025) Meta Graph API. The legacy page_impressions / page_fans / page_fan_adds / page_fan_removes metrics were deprecated by Meta on November 15, 2025 and are NOT accepted by this endpoint. Use the replacements below. Because Meta did not provide direct adds/removes replacements, Zernio synthesizes followers_gained / followers_lost from the daily follower snapshotter.  Max 89 days, defaults to last 30 days. Requires the Analytics add-on.
pub async fn get_facebook_page_insights(
    configuration: &configuration::Configuration,
    account_id: &str,
    metrics: Option<&str>,
    since: Option<String>,
    until: Option<String>,
    metric_type: Option<&str>,
) -> Result<models::InstagramAccountInsightsResponse, Error<GetFacebookPageInsightsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_account_id = account_id;
    let p_query_metrics = metrics;
    let p_query_since = since;
    let p_query_until = until;
    let p_query_metric_type = metric_type;

    let uri_str = format!(
        "{}/v1/analytics/facebook/page-insights",
        configuration.base_path
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("accountId", &p_query_account_id.to_string())]);
    if let Some(ref param_value) = p_query_metrics {
        req_builder = req_builder.query(&[("metrics", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_since {
        req_builder = req_builder.query(&[("since", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_until {
        req_builder = req_builder.query(&[("until", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_metric_type {
        req_builder = req_builder.query(&[("metricType", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::InstagramAccountInsightsResponse`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::InstagramAccountInsightsResponse`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetFacebookPageInsightsError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns the reaction breakdown for a Facebook Page post: a count per reaction type plus the overall total.  The whole breakdown is fetched in a single Graph call. Note that the post analytics endpoint reports only an aggregate reaction count (surfaced there as `likes`), so use this endpoint when you need per-type counts.
pub async fn get_facebook_post_reactions(
    configuration: &configuration::Configuration,
    account_id: &str,
    post_id: &str,
) -> Result<models::GetFacebookPostReactions200Response, Error<GetFacebookPostReactionsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_account_id = account_id;
    let p_query_post_id = post_id;

    let uri_str = format!(
        "{}/v1/accounts/{accountId}/facebook-post-reactions",
        configuration.base_path,
        accountId = crate::apis::urlencode(p_path_account_id)
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("postId", &p_query_post_id.to_string())]);
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetFacebookPostReactions200Response`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GetFacebookPostReactions200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetFacebookPostReactionsError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns follower count history and growth metrics for connected social accounts. Requires analytics add-on subscription. Follower counts are refreshed once per day.
pub async fn get_follower_stats(
    configuration: &configuration::Configuration,
    account_ids: Option<&str>,
    profile_id: Option<&str>,
    from_date: Option<String>,
    to_date: Option<String>,
    granularity: Option<&str>,
) -> Result<models::FollowerStatsResponse, Error<GetFollowerStatsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_account_ids = account_ids;
    let p_query_profile_id = profile_id;
    let p_query_from_date = from_date;
    let p_query_to_date = to_date;
    let p_query_granularity = granularity;

    let uri_str = format!("{}/v1/accounts/follower-stats", configuration.base_path);
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    if let Some(ref param_value) = p_query_account_ids {
        req_builder = req_builder.query(&[("accountIds", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_profile_id {
        req_builder = req_builder.query(&[("profileId", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_from_date {
        req_builder = req_builder.query(&[("fromDate", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_to_date {
        req_builder = req_builder.query(&[("toDate", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_granularity {
        req_builder = req_builder.query(&[("granularity", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::FollowerStatsResponse`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::FollowerStatsResponse`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetFollowerStatsError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns daily performance metrics for a Google Business Profile location. Metrics include impressions (Maps/Search, desktop/mobile), website clicks, call clicks, direction requests, conversations, bookings, and food orders. Data may be delayed 2-3 days. Max 18 months of historical data. Requires the Analytics add-on.
pub async fn get_google_business_performance(
    configuration: &configuration::Configuration,
    account_id: &str,
    metrics: Option<&str>,
    start_date: Option<String>,
    end_date: Option<String>,
) -> Result<models::GetGoogleBusinessPerformance200Response, Error<GetGoogleBusinessPerformanceError>>
{
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_account_id = account_id;
    let p_query_metrics = metrics;
    let p_query_start_date = start_date;
    let p_query_end_date = end_date;

    let uri_str = format!(
        "{}/v1/analytics/googlebusiness/performance",
        configuration.base_path
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("accountId", &p_query_account_id.to_string())]);
    if let Some(ref param_value) = p_query_metrics {
        req_builder = req_builder.query(&[("metrics", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_start_date {
        req_builder = req_builder.query(&[("startDate", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_end_date {
        req_builder = req_builder.query(&[("endDate", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetGoogleBusinessPerformance200Response`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GetGoogleBusinessPerformance200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetGoogleBusinessPerformanceError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns search keywords that triggered impressions for a Google Business Profile location. Data is aggregated monthly. Keywords below a minimum impression threshold set by Google are excluded. Max 18 months of historical data. Requires the Analytics add-on.
pub async fn get_google_business_search_keywords(
    configuration: &configuration::Configuration,
    account_id: &str,
    start_month: Option<&str>,
    end_month: Option<&str>,
) -> Result<
    models::GetGoogleBusinessSearchKeywords200Response,
    Error<GetGoogleBusinessSearchKeywordsError>,
> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_account_id = account_id;
    let p_query_start_month = start_month;
    let p_query_end_month = end_month;

    let uri_str = format!(
        "{}/v1/analytics/googlebusiness/search-keywords",
        configuration.base_path
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("accountId", &p_query_account_id.to_string())]);
    if let Some(ref param_value) = p_query_start_month {
        req_builder = req_builder.query(&[("startMonth", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_end_month {
        req_builder = req_builder.query(&[("endMonth", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetGoogleBusinessSearchKeywords200Response`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GetGoogleBusinessSearchKeywords200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetGoogleBusinessSearchKeywordsError> =
            serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns account-level Instagram insights such as reach, views, accounts engaged, and total interactions. These metrics reflect the entire account's performance across all content surfaces (feed, stories, explore, profile), and are fundamentally different from post-level metrics. Data may be delayed up to 48 hours. Max 90 days, defaults to last 30 days. Requires the Analytics add-on.
pub async fn get_instagram_account_insights(
    configuration: &configuration::Configuration,
    account_id: &str,
    metrics: Option<&str>,
    since: Option<String>,
    until: Option<String>,
    metric_type: Option<&str>,
    breakdown: Option<&str>,
) -> Result<models::InstagramAccountInsightsResponse, Error<GetInstagramAccountInsightsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_account_id = account_id;
    let p_query_metrics = metrics;
    let p_query_since = since;
    let p_query_until = until;
    let p_query_metric_type = metric_type;
    let p_query_breakdown = breakdown;

    let uri_str = format!(
        "{}/v1/analytics/instagram/account-insights",
        configuration.base_path
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("accountId", &p_query_account_id.to_string())]);
    if let Some(ref param_value) = p_query_metrics {
        req_builder = req_builder.query(&[("metrics", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_since {
        req_builder = req_builder.query(&[("since", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_until {
        req_builder = req_builder.query(&[("until", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_metric_type {
        req_builder = req_builder.query(&[("metricType", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_breakdown {
        req_builder = req_builder.query(&[("breakdown", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::InstagramAccountInsightsResponse`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::InstagramAccountInsightsResponse`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetInstagramAccountInsightsError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns audience demographic insights for an Instagram account, broken down by age, city, country, and/or gender. Requires at least 100 followers. Returns top 45 entries per dimension. Data may be delayed up to 48 hours. Requires the Analytics add-on.
pub async fn get_instagram_demographics(
    configuration: &configuration::Configuration,
    account_id: &str,
    metric: Option<&str>,
    breakdown: Option<&str>,
    timeframe: Option<&str>,
) -> Result<models::InstagramDemographicsResponse, Error<GetInstagramDemographicsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_account_id = account_id;
    let p_query_metric = metric;
    let p_query_breakdown = breakdown;
    let p_query_timeframe = timeframe;

    let uri_str = format!(
        "{}/v1/analytics/instagram/demographics",
        configuration.base_path
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("accountId", &p_query_account_id.to_string())]);
    if let Some(ref param_value) = p_query_metric {
        req_builder = req_builder.query(&[("metric", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_breakdown {
        req_builder = req_builder.query(&[("breakdown", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_timeframe {
        req_builder = req_builder.query(&[("timeframe", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::InstagramDemographicsResponse`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::InstagramDemographicsResponse`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetInstagramDemographicsError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns a daily running Instagram follower count time series, served from Zernio's cross-platform daily snapshotter. Exists because Meta removed follower_count from the /insights endpoint in Graph API v22+ and never exposed a historical daily series via any public API.  Response envelope matches /v1/analytics/instagram/account-insights so the same client handling works. Max 89 days, defaults to last 30 days. Requires the Analytics add-on.
pub async fn get_instagram_follower_history(
    configuration: &configuration::Configuration,
    account_id: &str,
    metrics: Option<&str>,
    since: Option<String>,
    until: Option<String>,
    metric_type: Option<&str>,
) -> Result<models::InstagramAccountInsightsResponse, Error<GetInstagramFollowerHistoryError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_account_id = account_id;
    let p_query_metrics = metrics;
    let p_query_since = since;
    let p_query_until = until;
    let p_query_metric_type = metric_type;

    let uri_str = format!(
        "{}/v1/analytics/instagram/follower-history",
        configuration.base_path
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("accountId", &p_query_account_id.to_string())]);
    if let Some(ref param_value) = p_query_metrics {
        req_builder = req_builder.query(&[("metrics", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_since {
        req_builder = req_builder.query(&[("since", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_until {
        req_builder = req_builder.query(&[("until", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_metric_type {
        req_builder = req_builder.query(&[("metricType", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::InstagramAccountInsightsResponse`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::InstagramAccountInsightsResponse`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetInstagramFollowerHistoryError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns aggregate analytics across all posts for a LinkedIn personal account. Only includes posts published through Zernio (LinkedIn API limitation). Org accounts should use /v1/analytics instead. Requires r_member_postAnalytics scope. Saves (POST_SAVE) and sends (POST_SEND) are available for personal accounts; organization pages always return 0 for these two metrics because LinkedIn does not expose them on the organization analytics endpoint.
pub async fn get_linked_in_aggregate_analytics(
    configuration: &configuration::Configuration,
    account_id: &str,
    aggregation: Option<&str>,
    start_date: Option<String>,
    end_date: Option<String>,
    metrics: Option<&str>,
) -> Result<
    models::GetLinkedInAggregateAnalytics200Response,
    Error<GetLinkedInAggregateAnalyticsError>,
> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_account_id = account_id;
    let p_query_aggregation = aggregation;
    let p_query_start_date = start_date;
    let p_query_end_date = end_date;
    let p_query_metrics = metrics;

    let uri_str = format!(
        "{}/v1/accounts/{accountId}/linkedin-aggregate-analytics",
        configuration.base_path,
        accountId = crate::apis::urlencode(p_path_account_id)
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    if let Some(ref param_value) = p_query_aggregation {
        req_builder = req_builder.query(&[("aggregation", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_start_date {
        req_builder = req_builder.query(&[("startDate", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_end_date {
        req_builder = req_builder.query(&[("endDate", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_metrics {
        req_builder = req_builder.query(&[("metrics", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetLinkedInAggregateAnalytics200Response`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GetLinkedInAggregateAnalytics200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetLinkedInAggregateAnalyticsError> =
            serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns aggregate analytics for a LinkedIn organization page. Parallel to /v1/accounts/{id}/linkedin-aggregate-analytics (which handles personal accounts only). Backed by LinkedIn's organizationalEntityShareStatistics, organizationalEntityFollowerStatistics, and organizationPageStatistics endpoints.  Response shape matches /v1/analytics/instagram/account-insights. Max 89 days, defaults to last 30 days. Requires the Analytics add-on.  Scope requirements: r_organization_social, r_organization_followers, and r_organization_admin must all be present on the account. Accounts connected before these scopes were included in the OAuth flow will return 412 with a reauth hint.  Enforced by this endpoint:   - Page-view metrics accept only metricType=total_value (LinkedIn omits per-day     segmentation even when the API is called with DAY granularity, so a time-series     response would be meaningless).   - Date range capped at 89 days.  LinkedIn-side platform limits (not re-enforced here, but worth knowing for larger ranges in a future release):   - Follower stats: rolling 12-month window, end must be no later than 2 days ago.   - Share stats: rolling 12-month window.
pub async fn get_linked_in_org_aggregate_analytics(
    configuration: &configuration::Configuration,
    account_id: &str,
    metrics: Option<&str>,
    since: Option<String>,
    until: Option<String>,
    metric_type: Option<&str>,
) -> Result<models::InstagramAccountInsightsResponse, Error<GetLinkedInOrgAggregateAnalyticsError>>
{
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_account_id = account_id;
    let p_query_metrics = metrics;
    let p_query_since = since;
    let p_query_until = until;
    let p_query_metric_type = metric_type;

    let uri_str = format!(
        "{}/v1/analytics/linkedin/org-aggregate-analytics",
        configuration.base_path
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("accountId", &p_query_account_id.to_string())]);
    if let Some(ref param_value) = p_query_metrics {
        req_builder = req_builder.query(&[("metrics", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_since {
        req_builder = req_builder.query(&[("since", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_until {
        req_builder = req_builder.query(&[("until", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_metric_type {
        req_builder = req_builder.query(&[("metricType", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::InstagramAccountInsightsResponse`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::InstagramAccountInsightsResponse`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetLinkedInOrgAggregateAnalyticsError> =
            serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns analytics for a specific LinkedIn post by URN. Works for both personal and organization accounts. Saves and sends are only populated for personal accounts (LinkedIn does not expose these metrics on the organization analytics endpoint).
pub async fn get_linked_in_post_analytics(
    configuration: &configuration::Configuration,
    account_id: &str,
    urn: &str,
) -> Result<models::GetLinkedInPostAnalytics200Response, Error<GetLinkedInPostAnalyticsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_account_id = account_id;
    let p_query_urn = urn;

    let uri_str = format!(
        "{}/v1/accounts/{accountId}/linkedin-post-analytics",
        configuration.base_path,
        accountId = crate::apis::urlencode(p_path_account_id)
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("urn", &p_query_urn.to_string())]);
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetLinkedInPostAnalytics200Response`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GetLinkedInPostAnalytics200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetLinkedInPostAnalyticsError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns individual reactions for a specific LinkedIn post, including reactor profiles (name, headline/job title, profile picture, profile URL, reaction type). Only works for organization/company page accounts. LinkedIn restricts reaction data for personal profiles (r_member_social_feed is a closed permission).
pub async fn get_linked_in_post_reactions(
    configuration: &configuration::Configuration,
    account_id: &str,
    urn: &str,
    limit: Option<i32>,
    cursor: Option<&str>,
) -> Result<models::GetLinkedInPostReactions200Response, Error<GetLinkedInPostReactionsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_account_id = account_id;
    let p_query_urn = urn;
    let p_query_limit = limit;
    let p_query_cursor = cursor;

    let uri_str = format!(
        "{}/v1/accounts/{accountId}/linkedin-post-reactions",
        configuration.base_path,
        accountId = crate::apis::urlencode(p_path_account_id)
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("urn", &p_query_urn.to_string())]);
    if let Some(ref param_value) = p_query_limit {
        req_builder = req_builder.query(&[("limit", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_cursor {
        req_builder = req_builder.query(&[("cursor", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetLinkedInPostReactions200Response`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GetLinkedInPostReactions200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetLinkedInPostReactionsError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns a daily timeline of analytics metrics for a specific post, showing how impressions, likes, and other metrics evolved day-by-day since publishing. Each row represents one day of data per platform. For multi-platform Zernio posts, returns separate rows for each platform. Requires the Analytics add-on.
pub async fn get_post_timeline(
    configuration: &configuration::Configuration,
    post_id: &str,
    from_date: Option<String>,
    to_date: Option<String>,
) -> Result<models::GetPostTimeline200Response, Error<GetPostTimelineError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_post_id = post_id;
    let p_query_from_date = from_date;
    let p_query_to_date = to_date;

    let uri_str = format!("{}/v1/analytics/post-timeline", configuration.base_path);
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("postId", &p_query_post_id.to_string())]);
    if let Some(ref param_value) = p_query_from_date {
        req_builder = req_builder.query(&[("fromDate", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_to_date {
        req_builder = req_builder.query(&[("toDate", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetPostTimeline200Response`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GetPostTimeline200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetPostTimelineError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns the correlation between posting frequency (posts per week) and engagement rate, broken down by platform. Helps find the optimal posting cadence for each platform. Each row represents a specific (platform, posts_per_week) combination with the average engagement rate observed across all weeks matching that frequency. Requires the Analytics add-on.
pub async fn get_posting_frequency(
    configuration: &configuration::Configuration,
    platform: Option<&str>,
    profile_id: Option<&str>,
    account_id: Option<&str>,
    source: Option<&str>,
) -> Result<models::GetPostingFrequency200Response, Error<GetPostingFrequencyError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_platform = platform;
    let p_query_profile_id = profile_id;
    let p_query_account_id = account_id;
    let p_query_source = source;

    let uri_str = format!("{}/v1/analytics/posting-frequency", configuration.base_path);
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    if let Some(ref param_value) = p_query_platform {
        req_builder = req_builder.query(&[("platform", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_profile_id {
        req_builder = req_builder.query(&[("profileId", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_account_id {
        req_builder = req_builder.query(&[("accountId", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_source {
        req_builder = req_builder.query(&[("source", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetPostingFrequency200Response`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GetPostingFrequency200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetPostingFrequencyError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns account-level TikTok insights from /v2/user/info/ (live) plus historical time series joined from Zernio's daily snapshotter (AccountStats).  Response shape matches /v1/analytics/instagram/account-insights. Max 89 days, defaults to last 30 days. Requires the Analytics add-on and the user.info.stats scope on the account (412 if missing).  Scope intentionally narrow. TikTok's public API exposes only the four counter metrics below. The deep metrics that live in TikTok Studio are NOT available on any public TikTok API, even for Business accounts:   - profile_views   - account-level impressions / reach   - follower inflow / outflow breakdown   - video watch time, average watch time, full-watched rate   - impression_sources (FYP / Following / Hashtag / Search / Personal profile)  TikTok's Research API doesn't expose those fields either, and is restricted to non-commercial academic use per TikTok's eligibility policy. There is no public API workaround. Post-level metrics (views, likes, comments, shares per video) are available via /v1/analytics?postId=... from TikTok's /v2/video/query/.
pub async fn get_tik_tok_account_insights(
    configuration: &configuration::Configuration,
    account_id: &str,
    metrics: Option<&str>,
    since: Option<String>,
    until: Option<String>,
    metric_type: Option<&str>,
) -> Result<models::InstagramAccountInsightsResponse, Error<GetTikTokAccountInsightsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_account_id = account_id;
    let p_query_metrics = metrics;
    let p_query_since = since;
    let p_query_until = until;
    let p_query_metric_type = metric_type;

    let uri_str = format!(
        "{}/v1/analytics/tiktok/account-insights",
        configuration.base_path
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("accountId", &p_query_account_id.to_string())]);
    if let Some(ref param_value) = p_query_metrics {
        req_builder = req_builder.query(&[("metrics", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_since {
        req_builder = req_builder.query(&[("since", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_until {
        req_builder = req_builder.query(&[("until", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_metric_type {
        req_builder = req_builder.query(&[("metricType", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::InstagramAccountInsightsResponse`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::InstagramAccountInsightsResponse`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetTikTokAccountInsightsError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns channel-scoped aggregate metrics from YouTube Analytics API v2. Saves you from looping /v1/analytics/youtube/daily-views over every video when you only need channel totals.  Response shape matches /v1/analytics/instagram/account-insights so the same client handling works. Requires yt-analytics.readonly scope (412 with reauthorizeUrl if missing). Data has a 2-3 day delay (endDate is clamped accordingly). Max 89 days, defaults to last 30 days. Requires the Analytics add-on.  NOT exposed: impressions (Studio thumbnail impressions) and impressionsClickThroughRate. YouTube Analytics API v2 does not expose these for any principal type, not channel owners, not Partner Program channels, not content owners with CMS access. The only way to get them is Studio CSV export. This is a Google-side limitation.
pub async fn get_you_tube_channel_insights(
    configuration: &configuration::Configuration,
    account_id: &str,
    metrics: Option<&str>,
    since: Option<String>,
    until: Option<String>,
    metric_type: Option<&str>,
) -> Result<models::InstagramAccountInsightsResponse, Error<GetYouTubeChannelInsightsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_account_id = account_id;
    let p_query_metrics = metrics;
    let p_query_since = since;
    let p_query_until = until;
    let p_query_metric_type = metric_type;

    let uri_str = format!(
        "{}/v1/analytics/youtube/channel-insights",
        configuration.base_path
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("accountId", &p_query_account_id.to_string())]);
    if let Some(ref param_value) = p_query_metrics {
        req_builder = req_builder.query(&[("metrics", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_since {
        req_builder = req_builder.query(&[("since", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_until {
        req_builder = req_builder.query(&[("until", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_metric_type {
        req_builder = req_builder.query(&[("metricType", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::InstagramAccountInsightsResponse`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::InstagramAccountInsightsResponse`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetYouTubeChannelInsightsError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns daily view counts for a YouTube video including views, watch time, and subscriber changes. Requires yt-analytics.readonly scope (re-authorization may be needed). Data has a 2-3 day delay. Max 90 days, defaults to last 30 days.
pub async fn get_you_tube_daily_views(
    configuration: &configuration::Configuration,
    video_id: &str,
    account_id: &str,
    start_date: Option<String>,
    end_date: Option<String>,
) -> Result<models::YouTubeDailyViewsResponse, Error<GetYouTubeDailyViewsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_video_id = video_id;
    let p_query_account_id = account_id;
    let p_query_start_date = start_date;
    let p_query_end_date = end_date;

    let uri_str = format!(
        "{}/v1/analytics/youtube/daily-views",
        configuration.base_path
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("videoId", &p_query_video_id.to_string())]);
    req_builder = req_builder.query(&[("accountId", &p_query_account_id.to_string())]);
    if let Some(ref param_value) = p_query_start_date {
        req_builder = req_builder.query(&[("startDate", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_end_date {
        req_builder = req_builder.query(&[("endDate", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::YouTubeDailyViewsResponse`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::YouTubeDailyViewsResponse`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetYouTubeDailyViewsError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns audience demographic insights for a YouTube channel, broken down by age, gender, and/or country. Age and gender values are viewer percentages (0-100). Country values are view counts. Data is based on signed-in viewers only, with a 2-3 day delay. Requires the Analytics add-on.
pub async fn get_you_tube_demographics(
    configuration: &configuration::Configuration,
    account_id: &str,
    breakdown: Option<&str>,
    start_date: Option<String>,
    end_date: Option<String>,
) -> Result<models::YouTubeDemographicsResponse, Error<GetYouTubeDemographicsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_account_id = account_id;
    let p_query_breakdown = breakdown;
    let p_query_start_date = start_date;
    let p_query_end_date = end_date;

    let uri_str = format!(
        "{}/v1/analytics/youtube/demographics",
        configuration.base_path
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("accountId", &p_query_account_id.to_string())]);
    if let Some(ref param_value) = p_query_breakdown {
        req_builder = req_builder.query(&[("breakdown", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_start_date {
        req_builder = req_builder.query(&[("startDate", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_end_date {
        req_builder = req_builder.query(&[("endDate", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::YouTubeDemographicsResponse`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::YouTubeDemographicsResponse`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetYouTubeDemographicsError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns the audience retention curve for a single YouTube video, plus the video's duration for rendering the curve on a time axis. The curve has up to 100 points (elapsedVideoTimeRatio 0.01-1.0) aggregated over the whole date range; YouTube does not support per-day retention breakdowns.  audienceWatchRatio is the absolute share of viewers watching at that point in the video and can exceed 1 (rewinds and looping, common on Shorts). relativeRetentionPerformance compares against videos of similar length (0 = worst, 0.5 = median, 1 = best). YouTube returns an empty curve for videos with very few views or before analytics processing completes (2-3 day delay).  Requires yt-analytics.readonly scope (re-authorization may be needed).
pub async fn get_you_tube_video_retention(
    configuration: &configuration::Configuration,
    video_id: &str,
    account_id: &str,
    start_date: Option<String>,
    end_date: Option<String>,
) -> Result<models::YouTubeVideoRetentionResponse, Error<GetYouTubeVideoRetentionError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_video_id = video_id;
    let p_query_account_id = account_id;
    let p_query_start_date = start_date;
    let p_query_end_date = end_date;

    let uri_str = format!(
        "{}/v1/analytics/youtube/video-retention",
        configuration.base_path
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("videoId", &p_query_video_id.to_string())]);
    req_builder = req_builder.query(&[("accountId", &p_query_account_id.to_string())]);
    if let Some(ref param_value) = p_query_start_date {
        req_builder = req_builder.query(&[("startDate", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_end_date {
        req_builder = req_builder.query(&[("endDate", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::YouTubeVideoRetentionResponse`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::YouTubeVideoRetentionResponse`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetYouTubeVideoRetentionError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Fetch an account's latest external posts (published directly on the platform, not through Zernio) on demand, so a just-published post is retrievable within seconds instead of waiting for the background sync (which refreshes each account at most every ~90 minutes).  Primary use case: verifying a submitted post. When a user publishes on the platform and immediately pastes the post URL into your app, call this with `accountId` plus `url` (or `postId`) to confirm the post exists and return its metadata.  Behavior: - We check our stored copy first and return immediately if the post is already known (no platform call). - Otherwise we fetch the account's latest posts live from the platform, then match and return the submitted post. - Requests are debounced per account (~15s): if the account was just synced, the live fetch is skipped.  `accountId` is required — a post URL or id alone cannot be resolved to an account, and the account must be connected to Zernio (we use its token to read the platform). Supported for every platform with a listing API (Instagram, Facebook, TikTok, YouTube, X, Threads, Pinterest, Reddit, Bluesky, Google Business, and LinkedIn organization accounts; LinkedIn personal accounts are not supported).  `url` accepts any format the platform uses (e.g. `instagram.com/p/…`, `instagram.com/reel/…`, `youtu.be/…`, `youtube.com/shorts/…`, `tiktok.com/@user/video/…`, and `vm.tiktok.com` short links). Pass `postId` (the platform media/video id) as an alternative locator.  Note: post-level analytics (reach, impressions) still carry the platform's own delay (e.g. ~24h on Instagram). This endpoint confirms the post exists and returns its metadata plus basic engagement (likes, comments), not delayed insights.
pub async fn sync_external_posts(
    configuration: &configuration::Configuration,
    sync_external_posts_request: models::SyncExternalPostsRequest,
) -> Result<models::SyncExternalPosts200Response, Error<SyncExternalPostsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_body_sync_external_posts_request = sync_external_posts_request;

    let uri_str = format!("{}/v1/posts/sync-external", configuration.base_path);
    let mut req_builder = configuration
        .client
        .request(reqwest::Method::POST, &uri_str);

    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };
    req_builder = req_builder.json(&p_body_sync_external_posts_request);

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::SyncExternalPosts200Response`"))),
            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::SyncExternalPosts200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<SyncExternalPostsError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}
