"""
ODS Models - Template Input
Template input data structures (assets, logos, texts).
Python equivalent of template input from design-data-microservices.
"""

from __future__ import annotations

from typing import List, Optional, Dict, Any, Union, TYPE_CHECKING
from datetime import datetime
from pydantic import BaseModel, Field, model_serializer
from ods_types import ImageMimeType, WhenToUseLogoEnum
from ods_models.guides import GuideDoc
from ods_models.font import Font

if TYPE_CHECKING:
    from ods_models.brand import Brand


class Asset(BaseModel):
    """
    Asset data structure.
    Represents an image asset with metadata and guides.
    parsing_label is optional to support items in groups (which use the group's parsing_label).
    """
    id: Optional[str] = None
    width: int
    height: int
    mime_type: ImageMimeType
    parsing_label: Optional[str] = None
    guides: Optional[List[GuideDoc]] = []
    original_image_id: Optional[str] = None
    description: Optional[str] = None
    name: Optional[str] = None
    s3Location: Dict[str, Any] = {}
    wer_ids: Optional[List[str]] = None
    workflow_registry_ids: Optional[List[str]] = None


class Logo(BaseModel):
    """
    Logo data structure.
    Represents a logo image with metadata and guides.
    parsing_label is optional to support items in groups (which use the group's parsing_label).
    """
    image_id: Optional[str] = None
    name: Optional[str] = None
    mime_type: ImageMimeType
    width: int
    height: int
    parsing_label: Optional[str] = None
    s3Location: Dict[str, Any] = {}
    guides: Optional[List[GuideDoc]] = None
    description: Optional[str] = None
    wer_id: Optional[str] = None
    workflow_registry_id: Optional[str] = None
    when_to_use_hint: Optional[str] = None  # when to use this logo (e.g. "logo", "icon", "background", "other")
    when_to_use_enum: Optional[WhenToUseLogoEnum] = None


class Text(BaseModel):
    """
    Text data structure.
    Represents a text input with localization support.
    parsing_label is optional to support items in groups (which use the group's parsing_label).
    """
    id: Optional[str] = None
    value: str
    parsing_label: Optional[str] = None
    isoCode: str
    font: Optional[Font] = None


class InputGroup(BaseModel):
    """
    Input group structure.
    Groups multiple items (assets and logos) under a single parsing_label.
    Items can be mixed types (Asset or Logo) in the same array.
    Note: Items in groups do NOT have parsing_label - only the group itself has parsing_label.
    Items use the group's parsing_label when processed.
    Note: Groups only support Asset and Logo items, not Text items.
    """
    parsing_label: str
    items: List[Union[Asset, Logo]]

    @model_serializer
    def serialize_model(self, serializer=None):
        """
        Custom serializer that adds 'type' field to each item for renderer compatibility.
        The renderer expects group items to have a 'type' field ("asset" or "logo")
        because groups.items is a mixed array and the renderer cannot infer the type
        from the array name (unlike inputs.assets, inputs.logos which are typed arrays).
        """
        items_with_type = []
        for item in self.items:
            item_dict = item.model_dump()
            # Add type field based on item class
            if isinstance(item, Asset):
                item_dict['type'] = 'asset'
            elif isinstance(item, Logo):
                item_dict['type'] = 'logo'
            items_with_type.append(item_dict)
        
        return {
            'parsing_label': self.parsing_label,
            'items': items_with_type
        }


class TemplateInputDesignData(BaseModel):
    """
    Template input design data structure.
    Contains all assets, logos, texts, groups, and extra data for a template.
    """
    assets: List[Asset] = []
    logos: List[Logo] = []
    texts: List[Text] = []
    brands: Optional[List[str]] = None
    groups: Optional[List[InputGroup]] = None  # Array of groups, each with parsing_label and items (Asset/Logo only)
    extra_data: Dict[str, Any] = {}


class TemplateInput(BaseModel):
    """
    Template input object (a template input instance validated against a template registry).
    Represents a complete set of design data for rendering.
    """
    id: str
    template_registry_id: str
    inputs: TemplateInputDesignData
    created_at: datetime = Field(default_factory=datetime.utcnow)
    updated_at: datetime = Field(default_factory=datetime.utcnow)
    created_by: str
    updated_by: str
    account_id: str
    studio_id: str
    tags: List[str] = Field(default_factory=list)
    name: Optional[str] = None
    canvas_key: Optional[str] = None


class TemplateInputWithoutId(BaseModel):
    """Template input for insert operations (no id field)"""
    template_registry_id: str
    inputs: TemplateInputDesignData
    created_at: datetime = Field(default_factory=datetime.utcnow)
    updated_at: datetime = Field(default_factory=datetime.utcnow)
    updated_by: str
    created_by: str
    account_id: str
    studio_id: str
    tags: List[str] = Field(default_factory=list)
    name: Optional[str] = None
    canvas_key: Optional[str] = None


class TemplateInputForCreate(BaseModel):
    """Partial template input for create operations"""
    template_registry_id: str
    inputs: TemplateInputDesignData
    created_by: str
    account_id: str
    studio_id: str
    tags: List[str] = Field(default_factory=list)
    name: Optional[str] = None
    canvas_key: Optional[str] = None
