/*
 * 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 crate::models;
use serde::{Deserialize, Serialize};

/// CreateCtwaAdRequest : In addition to the `required` list, the request must use EXACTLY ONE of the two shapes:  - Single-creative: `headline`, `body`, and one of   `imageUrl` / `video` (mutually exclusive). - Multi-creative: a non-empty `creatives[]` array. Top-level   `headline` / `body` / `imageUrl` / `video` must NOT be set   on this shape.  The route enforces this at the Zod boundary; OpenAPI's `required` cannot express the OR cleanly.
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct CreateCtwaAdRequest {
    /// Facebook or Instagram SocialAccount ID.
    #[serde(rename = "accountId")]
    pub account_id: String,
    /// Meta ad account ID, e.g. `act_123456789`.
    #[serde(rename = "adAccountId")]
    pub ad_account_id: String,
    /// Ad display name. Used to derive campaign / ad set names. On the multi-creative shape, each ad's Meta name gets a \" #N\" suffix (1-indexed) so Ads Manager shows them as a numbered batch.
    #[serde(rename = "name")]
    pub name: String,
    /// Single-creative shape only. Mutually exclusive with `creatives[]`.
    #[serde(rename = "headline", skip_serializing_if = "Option::is_none")]
    pub headline: Option<String>,
    /// Primary text shown above the image / video. Single-creative shape only. Mutually exclusive with `creatives[]`.
    #[serde(rename = "body", skip_serializing_if = "Option::is_none")]
    pub body: Option<String>,
    /// Image asset for single-creative shape. Mutually exclusive with `video` and with `creatives[]`. Required on the single-creative shape if `video` is not supplied.
    #[serde(rename = "imageUrl", skip_serializing_if = "Option::is_none")]
    pub image_url: Option<String>,
    #[serde(rename = "video", skip_serializing_if = "Option::is_none")]
    pub video: Option<Box<models::CreateCtwaAdRequestVideo>>,
    /// Multi-creative shape: N CTWA ads under one campaign + one ad set, sharing budget and targeting. Mutually exclusive with the top-level single-creative fields (`headline` / `body` / `imageUrl` / `video`). Each entry must supply its own headline, body, and exactly one of `imageUrl` / `video`.
    #[serde(rename = "creatives", skip_serializing_if = "Option::is_none")]
    pub creatives: Option<Vec<models::CreateCtwaAdRequestCreativesInner>>,
    /// Budget amount in the ad account's currency major units (e.g. dollars for USD, not cents). Must be > 0.
    #[serde(rename = "budgetAmount")]
    pub budget_amount: f64,
    #[serde(rename = "budgetType")]
    pub budget_type: BudgetType,
    /// ISO 4217 currency code matching the ad account's currency (e.g. `USD`). Optional; Meta infers from the ad account when omitted.
    #[serde(rename = "currency", skip_serializing_if = "Option::is_none")]
    pub currency: Option<String>,
    /// ISO 8601 datetime. Required when `budgetType` is `lifetime`.
    #[serde(rename = "endDate", skip_serializing_if = "Option::is_none")]
    pub end_date: Option<String>,
    /// ISO 3166-1 alpha-2 country codes. Defaults to `[\"US\"]` only when no other geo (`cities`, `regions`, `zips`, `metros`, `customLocations`) is supplied.
    #[serde(rename = "countries", skip_serializing_if = "Option::is_none")]
    pub countries: Option<Vec<String>>,
    /// City-level geo targeting for local CTWA campaigns (e.g. 25km radius around Milan). Each entry maps to Meta's TargetingGeoLocationCity. `key` is Meta's city ID (lookupable via GET /v1/ads/targeting/search). `radius` and `distance_unit` are coupled: set both or neither.
    #[serde(rename = "cities", skip_serializing_if = "Option::is_none")]
    pub cities: Option<Vec<models::CreateCtwaAdRequestCitiesInner>>,
    /// Region / state-level geo targeting. `key` is Meta's region ID (lookupable via GET /v1/ads/targeting/search?type=region).
    #[serde(rename = "regions", skip_serializing_if = "Option::is_none")]
    pub regions: Option<Vec<models::CreateCtwaAdRequestRegionsInner>>,
    /// ZIP / postal-code geo targeting. `key` is the platform's postal id resolved via /v1/ads/targeting/search.
    #[serde(rename = "zips", skip_serializing_if = "Option::is_none")]
    pub zips: Option<Vec<models::CreateCtwaAdRequestZipsInner>>,
    /// DMA / metro-area geo targeting. `key` is Meta's metro id (e.g. `DMA:807`).
    #[serde(rename = "metros", skip_serializing_if = "Option::is_none")]
    pub metros: Option<Vec<models::CreateCtwaAdRequestZipsInner>>,
    /// Point-radius geo (Meta `geo_locations.custom_locations`). Use for targeting a radius around a specific lat/long when no Meta city/region key fits. `distanceUnit` is required.
    #[serde(rename = "customLocations", skip_serializing_if = "Option::is_none")]
    pub custom_locations: Option<Vec<models::CreateCtwaAdRequestCustomLocationsInner>>,
    #[serde(rename = "ageMin", skip_serializing_if = "Option::is_none")]
    pub age_min: Option<i32>,
    #[serde(rename = "ageMax", skip_serializing_if = "Option::is_none")]
    pub age_max: Option<i32>,
    #[serde(rename = "interests", skip_serializing_if = "Option::is_none")]
    pub interests: Option<Vec<models::CreateStandaloneAdRequestBehaviorsInner>>,
    /// Custom audience ID to target.
    #[serde(rename = "audienceId", skip_serializing_if = "Option::is_none")]
    pub audience_id: Option<String>,
    /// Meta's Advantage+ audience expansion. `0` (default) keeps targeting strict; `1` lets Meta expand beyond the supplied targeting when its delivery system finds better matches. Always sent on CREATE (Meta requires it).
    #[serde(rename = "advantageAudience", skip_serializing_if = "Option::is_none")]
    pub advantage_audience: Option<AdvantageAudience>,
    /// Defaults to `OUTCOME_ENGAGEMENT` (the broadly-supported CTWA objective). `OUTCOME_SALES` and `OUTCOME_LEADS` require additional account configuration (Dataset linked to the WABA for sales) and may be rejected by Meta if missing.
    #[serde(rename = "objective", skip_serializing_if = "Option::is_none")]
    pub objective: Option<Objective>,
    /// Meta bid strategy applied to the shared ad set. Defaults to `LOWEST_COST_WITHOUT_CAP` (auto-bid) when omitted. `LOWEST_COST_WITH_BID_CAP` and `COST_CAP` require `bidAmount`. `LOWEST_COST_WITH_MIN_ROAS` requires `roasAverageFloor`. CTWA's `optimization_goal` is fixed to `CONVERSATIONS`, but the bid strategy is independent.
    #[serde(rename = "bidStrategy", skip_serializing_if = "Option::is_none")]
    pub bid_strategy: Option<BidStrategy>,
    /// Whole currency units (e.g. `5` = $5.00 on a USD account). Required when `bidStrategy` is `LOWEST_COST_WITH_BID_CAP` or `COST_CAP`; rejected otherwise.
    #[serde(rename = "bidAmount", skip_serializing_if = "Option::is_none")]
    pub bid_amount: Option<f64>,
    /// Decimal ROAS multiplier (e.g. `2.0` = 2.0× ROAS floor). Required when `bidStrategy` is `LOWEST_COST_WITH_MIN_ROAS`; rejected otherwise. Meta enforces its own upper bound server-side.
    #[serde(rename = "roasAverageFloor", skip_serializing_if = "Option::is_none")]
    pub roas_average_floor: Option<f64>,
    /// Name of the legal entity benefiting from the ad. Required by Meta when targeting EU users (DSA Article 26). Not enforced at schema level; enforced server-side when targeting intersects EU member states.
    #[serde(rename = "dsaBeneficiary", skip_serializing_if = "Option::is_none")]
    pub dsa_beneficiary: Option<String>,
    /// Name of the legal entity paying for the ad. Required by Meta when targeting EU users (DSA Article 26). Note Meta API spelling: dsa_payor (not dsa_payer).
    #[serde(rename = "dsaPayor", skip_serializing_if = "Option::is_none")]
    pub dsa_payor: Option<String>,
}

impl CreateCtwaAdRequest {
    /// In addition to the `required` list, the request must use EXACTLY ONE of the two shapes:  - Single-creative: `headline`, `body`, and one of   `imageUrl` / `video` (mutually exclusive). - Multi-creative: a non-empty `creatives[]` array. Top-level   `headline` / `body` / `imageUrl` / `video` must NOT be set   on this shape.  The route enforces this at the Zod boundary; OpenAPI's `required` cannot express the OR cleanly.
    pub fn new(
        account_id: String,
        ad_account_id: String,
        name: String,
        budget_amount: f64,
        budget_type: BudgetType,
    ) -> CreateCtwaAdRequest {
        CreateCtwaAdRequest {
            account_id,
            ad_account_id,
            name,
            headline: None,
            body: None,
            image_url: None,
            video: None,
            creatives: None,
            budget_amount,
            budget_type,
            currency: None,
            end_date: None,
            countries: None,
            cities: None,
            regions: None,
            zips: None,
            metros: None,
            custom_locations: None,
            age_min: None,
            age_max: None,
            interests: None,
            audience_id: None,
            advantage_audience: None,
            objective: None,
            bid_strategy: None,
            bid_amount: None,
            roas_average_floor: None,
            dsa_beneficiary: None,
            dsa_payor: None,
        }
    }
}
///
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum BudgetType {
    #[serde(rename = "daily")]
    Daily,
    #[serde(rename = "lifetime")]
    Lifetime,
}

impl Default for BudgetType {
    fn default() -> BudgetType {
        Self::Daily
    }
}
/// Meta's Advantage+ audience expansion. `0` (default) keeps targeting strict; `1` lets Meta expand beyond the supplied targeting when its delivery system finds better matches. Always sent on CREATE (Meta requires it).
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum AdvantageAudience {
    #[serde(rename = "0")]
    Variant0,
    #[serde(rename = "1")]
    Variant1,
}

impl Default for AdvantageAudience {
    fn default() -> AdvantageAudience {
        Self::Variant0
    }
}
/// Defaults to `OUTCOME_ENGAGEMENT` (the broadly-supported CTWA objective). `OUTCOME_SALES` and `OUTCOME_LEADS` require additional account configuration (Dataset linked to the WABA for sales) and may be rejected by Meta if missing.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum Objective {
    #[serde(rename = "OUTCOME_ENGAGEMENT")]
    OutcomeEngagement,
    #[serde(rename = "OUTCOME_SALES")]
    OutcomeSales,
    #[serde(rename = "OUTCOME_LEADS")]
    OutcomeLeads,
}

impl Default for Objective {
    fn default() -> Objective {
        Self::OutcomeEngagement
    }
}
/// Meta bid strategy applied to the shared ad set. Defaults to `LOWEST_COST_WITHOUT_CAP` (auto-bid) when omitted. `LOWEST_COST_WITH_BID_CAP` and `COST_CAP` require `bidAmount`. `LOWEST_COST_WITH_MIN_ROAS` requires `roasAverageFloor`. CTWA's `optimization_goal` is fixed to `CONVERSATIONS`, but the bid strategy is independent.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum BidStrategy {
    #[serde(rename = "LOWEST_COST_WITHOUT_CAP")]
    LowestCostWithoutCap,
    #[serde(rename = "LOWEST_COST_WITH_BID_CAP")]
    LowestCostWithBidCap,
    #[serde(rename = "COST_CAP")]
    CostCap,
    #[serde(rename = "LOWEST_COST_WITH_MIN_ROAS")]
    LowestCostWithMinRoas,
}

impl Default for BidStrategy {
    fn default() -> BidStrategy {
        Self::LowestCostWithoutCap
    }
}
