# generated by datamodel-codegen:
#   filename:  core/format.json
#   timestamp: 2026-02-28T17:39:50+00:00

from __future__ import annotations

from enum import Enum
from typing import Annotated, Any, Literal

from adcp.types.base import AdCPBaseModel
from pydantic import AnyUrl, ConfigDict, Field

from ..enums import (
    available_metric,
    disclosure_position,
    format_category,
    format_id_parameter,
    universal_macro,
)
from ..enums import wcag_level as wcag_level_1
from . import format_id as format_id_1
from . import overlay
from .requirements import (
    audio_asset_requirements,
    catalog_requirements,
    css_asset_requirements,
    daast_asset_requirements,
    html_asset_requirements,
    image_asset_requirements,
    javascript_asset_requirements,
    markdown_asset_requirements,
    text_asset_requirements,
    url_asset_requirements,
    vast_asset_requirements,
    video_asset_requirements,
    webhook_asset_requirements,
)


class SelectionMode(Enum):
    sequential = 'sequential'
    optimize = 'optimize'


class Responsive(AdCPBaseModel):
    height: bool
    width: bool


class Dimensions(AdCPBaseModel):
    aspect_ratio: Annotated[
        str | None,
        Field(
            description="Fixed aspect ratio constraint (e.g., '16:9', '4:3', '1:1')",
            pattern='^\\d+:\\d+$',
        ),
    ] = None
    height: Annotated[int | None, Field(description='Fixed height in pixels', ge=1)] = None
    max_height: Annotated[
        int | None, Field(description='Maximum height in pixels for responsive renders', ge=1)
    ] = None
    max_width: Annotated[
        int | None, Field(description='Maximum width in pixels for responsive renders', ge=1)
    ] = None
    min_height: Annotated[
        int | None, Field(description='Minimum height in pixels for responsive renders', ge=1)
    ] = None
    min_width: Annotated[
        int | None, Field(description='Minimum width in pixels for responsive renders', ge=1)
    ] = None
    responsive: Annotated[
        Responsive | None, Field(description='Indicates which dimensions are responsive/fluid')
    ] = None
    width: Annotated[int | None, Field(description='Fixed width in pixels', ge=1)] = None


class Renders(AdCPBaseModel):
    dimensions: Annotated[
        Dimensions, Field(description='Dimensions for this rendered piece (in pixels)')
    ]
    parameters_from_format_id: Annotated[
        bool | None,
        Field(
            description='When true, parameters for this render (dimensions and/or duration) are specified in the format_id. Used for template formats that accept parameters. Mutually exclusive with specifying dimensions object explicitly.'
        ),
    ] = None
    role: Annotated[
        str,
        Field(
            description="Semantic role of this rendered piece (e.g., 'primary', 'companion', 'mobile_variant')"
        ),
    ]


class Dimensions1(Dimensions):
    pass


class Renders1(AdCPBaseModel):
    dimensions: Annotated[
        Dimensions1 | None, Field(description='Dimensions for this rendered piece (in pixels)')
    ] = None
    parameters_from_format_id: Annotated[
        Literal[True],
        Field(
            description='When true, parameters for this render (dimensions and/or duration) are specified in the format_id. Used for template formats that accept parameters. Mutually exclusive with specifying dimensions object explicitly.'
        ),
    ]
    role: Annotated[
        str,
        Field(
            description="Semantic role of this rendered piece (e.g., 'primary', 'companion', 'mobile_variant')"
        ),
    ]


class Accessibility(AdCPBaseModel):
    requires_accessible_assets: Annotated[
        bool | None,
        Field(
            description='When true, all assets with x-accessibility fields must include those fields. For inspectable assets (image, video, audio), this means providing accessibility metadata like alt_text or captions. For opaque assets (HTML, JavaScript), this means providing self-declared accessibility properties.'
        ),
    ] = None
    wcag_level: Annotated[
        wcag_level_1.WcagLevel,
        Field(
            description='WCAG conformance level that this format achieves. For format-rendered creatives, the format guarantees this level. For opaque creatives, the format requires assets that self-certify to this level.'
        ),
    ]


class FormatCard(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    format_id: Annotated[
        format_id_1.FormatId,
        Field(
            description='Creative format defining the card layout (typically format_card_standard)'
        ),
    ]
    manifest: Annotated[
        dict[str, Any],
        Field(description='Asset manifest for rendering the card, structure defined by the format'),
    ]


class FormatCardDetailed(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    format_id: Annotated[
        format_id_1.FormatId,
        Field(
            description='Creative format defining the detailed card layout (typically format_card_detailed)'
        ),
    ]
    manifest: Annotated[
        dict[str, Any],
        Field(
            description='Asset manifest for rendering the detailed card, structure defined by the format'
        ),
    ]


class BaseGroupAsset(AdCPBaseModel):
    asset_id: Annotated[str, Field(description='Identifier for this asset within the group')]
    asset_role: Annotated[
        str | None,
        Field(
            description="Descriptive label for this asset's purpose. For documentation and UI display only — manifests key assets by asset_id, not asset_role."
        ),
    ] = None
    overlays: Annotated[
        list[overlay.Overlay] | None,
        Field(
            description="Publisher-controlled elements rendered on top of buyer content at this asset's position (e.g., carousel navigation arrows, slide indicators). Creative agents should avoid placing critical content within overlay bounds."
        ),
    ] = None
    required: Annotated[
        bool,
        Field(description='Whether this asset is required within each repetition of the group'),
    ]


class BaseIndividualAsset(AdCPBaseModel):
    asset_id: Annotated[
        str,
        Field(
            description='Unique identifier for this asset. Creative manifests MUST use this exact value as the key in the assets object.'
        ),
    ]
    asset_role: Annotated[
        str | None,
        Field(
            description="Descriptive label for this asset's purpose (e.g., 'hero_image', 'logo', 'third_party_tracking'). For documentation and UI display only — manifests key assets by asset_id, not asset_role."
        ),
    ] = None
    item_type: Annotated[
        Literal['individual'],
        Field(description='Discriminator indicating this is an individual asset'),
    ]
    overlays: Annotated[
        list[overlay.Overlay] | None,
        Field(
            description="Publisher-controlled elements rendered on top of buyer content at this asset's position (e.g., video player controls, publisher logos). Creative agents should avoid placing critical content (CTAs, logos, key copy) within overlay bounds."
        ),
    ] = None
    required: Annotated[
        bool,
        Field(
            description='Whether this asset is required (true) or optional (false). Required assets must be provided for a valid creative. Optional assets enhance the creative but are not mandatory.'
        ),
    ]


class Assets(BaseIndividualAsset):
    asset_type: Literal['image'] = 'image'
    item_type: Literal['individual'] = 'individual'
    requirements: image_asset_requirements.ImageAssetRequirements | None = None


class Assets5(BaseIndividualAsset):
    asset_type: Literal['video'] = 'video'
    item_type: Literal['individual'] = 'individual'
    requirements: video_asset_requirements.VideoAssetRequirements | None = None


class Assets6(BaseIndividualAsset):
    asset_type: Literal['audio'] = 'audio'
    item_type: Literal['individual'] = 'individual'
    requirements: audio_asset_requirements.AudioAssetRequirements | None = None


class Assets7(BaseIndividualAsset):
    asset_type: Literal['text'] = 'text'
    item_type: Literal['individual'] = 'individual'
    requirements: text_asset_requirements.TextAssetRequirements | None = None


class Assets8(BaseIndividualAsset):
    asset_type: Literal['markdown'] = 'markdown'
    item_type: Literal['individual'] = 'individual'
    requirements: markdown_asset_requirements.MarkdownAssetRequirements | None = None


class Assets9(BaseIndividualAsset):
    asset_type: Literal['html'] = 'html'
    item_type: Literal['individual'] = 'individual'
    requirements: html_asset_requirements.HtmlAssetRequirements | None = None


class Assets10(BaseIndividualAsset):
    asset_type: Literal['css'] = 'css'
    item_type: Literal['individual'] = 'individual'
    requirements: css_asset_requirements.CssAssetRequirements | None = None


class Assets11(BaseIndividualAsset):
    asset_type: Literal['javascript'] = 'javascript'
    item_type: Literal['individual'] = 'individual'
    requirements: javascript_asset_requirements.JavascriptAssetRequirements | None = None


class Assets12(BaseIndividualAsset):
    asset_type: Literal['vast'] = 'vast'
    item_type: Literal['individual'] = 'individual'
    requirements: vast_asset_requirements.VastAssetRequirements | None = None


class Assets13(BaseIndividualAsset):
    asset_type: Literal['daast'] = 'daast'
    item_type: Literal['individual'] = 'individual'
    requirements: daast_asset_requirements.DaastAssetRequirements | None = None


class Assets14(BaseIndividualAsset):
    asset_type: Literal['url'] = 'url'
    item_type: Literal['individual'] = 'individual'
    requirements: url_asset_requirements.UrlAssetRequirements | None = None


class Assets15(BaseIndividualAsset):
    asset_type: Literal['webhook'] = 'webhook'
    item_type: Literal['individual'] = 'individual'
    requirements: webhook_asset_requirements.WebhookAssetRequirements | None = None


class Assets16(BaseIndividualAsset):
    asset_type: Literal['brief'] = 'brief'
    item_type: Literal['individual'] = 'individual'


class Assets17(BaseIndividualAsset):
    asset_type: Literal['catalog'] = 'catalog'
    item_type: Literal['individual'] = 'individual'
    requirements: catalog_requirements.CatalogRequirements | None = None


class Assets19(BaseGroupAsset):
    asset_type: Literal['image'] = 'image'
    requirements: image_asset_requirements.ImageAssetRequirements | None = None


class Assets20(BaseGroupAsset):
    asset_type: Literal['video'] = 'video'
    requirements: video_asset_requirements.VideoAssetRequirements | None = None


class Assets21(BaseGroupAsset):
    asset_type: Literal['audio'] = 'audio'
    requirements: audio_asset_requirements.AudioAssetRequirements | None = None


class Assets22(BaseGroupAsset):
    asset_type: Literal['text'] = 'text'
    requirements: text_asset_requirements.TextAssetRequirements | None = None


class Assets23(BaseGroupAsset):
    asset_type: Literal['markdown'] = 'markdown'
    requirements: markdown_asset_requirements.MarkdownAssetRequirements | None = None


class Assets24(BaseGroupAsset):
    asset_type: Literal['html'] = 'html'
    requirements: html_asset_requirements.HtmlAssetRequirements | None = None


class Assets25(BaseGroupAsset):
    asset_type: Literal['css'] = 'css'
    requirements: css_asset_requirements.CssAssetRequirements | None = None


class Assets26(BaseGroupAsset):
    asset_type: Literal['javascript'] = 'javascript'
    requirements: javascript_asset_requirements.JavascriptAssetRequirements | None = None


class Assets27(BaseGroupAsset):
    asset_type: Literal['vast'] = 'vast'
    requirements: vast_asset_requirements.VastAssetRequirements | None = None


class Assets28(BaseGroupAsset):
    asset_type: Literal['daast'] = 'daast'
    requirements: daast_asset_requirements.DaastAssetRequirements | None = None


class Assets29(BaseGroupAsset):
    asset_type: Literal['url'] = 'url'
    requirements: url_asset_requirements.UrlAssetRequirements | None = None


class Assets30(BaseGroupAsset):
    asset_type: Literal['webhook'] = 'webhook'
    requirements: webhook_asset_requirements.WebhookAssetRequirements | None = None


class Assets18(AdCPBaseModel):
    asset_group_id: Annotated[
        str, Field(description="Identifier for this asset group (e.g., 'product', 'slide', 'card')")
    ]
    assets: Annotated[
        list[
            Assets19
            | Assets20
            | Assets21
            | Assets22
            | Assets23
            | Assets24
            | Assets25
            | Assets26
            | Assets27
            | Assets28
            | Assets29
            | Assets30
        ],
        Field(description='Assets within each repetition of this group'),
    ]
    item_type: Annotated[
        Literal['repeatable_group'],
        Field(description='Discriminator indicating this is a repeatable asset group'),
    ]
    max_count: Annotated[int, Field(description='Maximum number of repetitions allowed', ge=1)]
    min_count: Annotated[
        int,
        Field(
            description='Minimum number of repetitions required (if group is required) or allowed (if optional)',
            ge=0,
        ),
    ]
    required: Annotated[
        bool,
        Field(
            description='Whether this asset group is required. If true, at least min_count repetitions must be provided.'
        ),
    ]
    selection_mode: Annotated[
        SelectionMode | None,
        Field(
            description="How the platform uses repetitions of this group. 'sequential' means all items display in order (carousels, playlists). 'optimize' means the platform selects the best-performing combination from alternatives (asset group optimization like Meta Advantage+ or Google Pmax)."
        ),
    ] = SelectionMode.sequential


class Format(AdCPBaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    accepts_parameters: Annotated[
        list[format_id_parameter.FormatIdParameter] | None,
        Field(
            description='List of parameters this format accepts in format_id. Template formats define which parameters (dimensions, duration, etc.) can be specified when instantiating the format. Empty or omitted means this is a concrete format with fixed parameters.'
        ),
    ] = None
    accessibility: Annotated[
        Accessibility | None,
        Field(
            description='Accessibility posture of this format. Declares the WCAG conformance level that creatives produced by this format will meet.'
        ),
    ] = None
    assets: Annotated[
        list[
            Assets
            | Assets5
            | Assets6
            | Assets7
            | Assets8
            | Assets9
            | Assets10
            | Assets11
            | Assets12
            | Assets13
            | Assets14
            | Assets15
            | Assets16
            | Assets17
            | Assets18
        ]
        | None,
        Field(
            description="Array of all assets supported for this format. Each asset is identified by its asset_id, which must be used as the key in creative manifests. Use the 'required' boolean on each asset to indicate whether it's mandatory."
        ),
    ] = None
    delivery: Annotated[
        dict[str, Any] | None,
        Field(description='Delivery method specifications (e.g., hosted, VAST, third-party tags)'),
    ] = None
    description: Annotated[
        str | None,
        Field(
            description='Plain text explanation of what this format does and what assets it requires'
        ),
    ] = None
    example_url: Annotated[
        AnyUrl | None,
        Field(
            description='Optional URL to showcase page with examples and interactive demos of this format'
        ),
    ] = None
    format_card: Annotated[
        FormatCard | None,
        Field(
            description='Optional standard visual card (300x400px) for displaying this format in user interfaces. Can be rendered via preview_creative or pre-generated.'
        ),
    ] = None
    format_card_detailed: Annotated[
        FormatCardDetailed | None,
        Field(
            description='Optional detailed card with carousel and full specifications. Provides rich format documentation similar to ad spec pages.'
        ),
    ] = None
    format_id: Annotated[
        format_id_1.FormatId,
        Field(description='Structured format identifier with agent URL and format name'),
    ]
    input_format_ids: Annotated[
        list[format_id_1.FormatId] | None,
        Field(
            description='Array of format IDs this format accepts as input creative manifests. When present, indicates this format can take existing creatives in these formats as input. Omit for formats that work from raw assets (images, text, etc.) rather than existing creatives.'
        ),
    ] = None
    name: Annotated[str, Field(description='Human-readable format name')]
    output_format_ids: Annotated[
        list[format_id_1.FormatId] | None,
        Field(
            description='Array of format IDs that this format can produce as output. When present, indicates this format can build creatives in these output formats (e.g., a multi-publisher template format might produce standard display formats across many publishers). Omit for formats that produce a single fixed output (the format itself).'
        ),
    ] = None
    renders: Annotated[
        list[Renders | Renders1] | None,
        Field(
            description='Specification of rendered pieces for this format. Most formats produce a single render. Companion ad formats (video + banner), adaptive formats, and multi-placement formats produce multiple renders. Each render specifies its role and dimensions.',
            min_length=1,
        ),
    ] = None
    reported_metrics: Annotated[
        list[available_metric.AvailableMetric] | None,
        Field(
            description='Metrics this format can produce in delivery reporting. Buyers receive the intersection of format reported_metrics and product available_metrics. If omitted, the format defers entirely to product-level metric declarations.',
            min_length=1,
        ),
    ] = None
    supported_disclosure_positions: Annotated[
        list[disclosure_position.DisclosurePosition] | None,
        Field(
            description='Disclosure positions this format can render. Buyers use this to determine whether a format can satisfy their compliance requirements before submitting a creative. When omitted, the format makes no disclosure rendering guarantees — creative agents SHOULD treat this as incompatible with briefs that require specific disclosure positions. Values correspond to positions on creative-brief.json required_disclosures.',
            min_length=1,
        ),
    ] = None
    supported_macros: Annotated[
        list[universal_macro.UniversalMacro | str] | None,
        Field(
            description='List of universal macros supported by this format (e.g., MEDIA_BUY_ID, CACHEBUSTER, DEVICE_ID). Used for validation and developer tooling. See docs/creative/universal-macros.mdx for full documentation.'
        ),
    ] = None
    type: Annotated[
        format_category.FormatCategory | None,
        Field(
            description='DEPRECATED: High-level category for this format. Use the assets array to understand creative requirements instead - it provides precise information about what asset types are needed.'
        ),
    ] = None
