"""Mapper for converting between AssetDB entity and Asset schemas"""
from typing import Union, Dict, Any
import uuid
from datetime import datetime

from src.models.entities import AssetDB
from src.models.schemas import (
    Asset,
    CharacterAsset,
    SceneAsset,
    PropAsset,
    OtherAsset,
    CreateAssetRequest,
    CreateCharacterAssetRequest,
    CreateSceneAssetRequest,
    CreatePropAssetRequest,
    CreateOtherAssetRequest,
    UpdateAssetRequest,
    GenerationRecord,
)


class AssetMapper:
    """Mapper for Asset entity and schemas"""
    
    @staticmethod
    def to_schema(db: AssetDB) -> Asset:
        """Convert AssetDB entity to Asset schema
        
        Args:
            db: AssetDB entity from database
            
        Returns:
            Asset schema (CharacterAsset, SceneAsset, PropAsset, or OtherAsset)
        """
        # Parse generations
        generations = []
        if db.generations:
            try:
                from pydantic import TypeAdapter
                adapter = TypeAdapter(list[GenerationRecord])
                generations = adapter.validate_python(db.generations)
            except Exception:
                generations = []
        
        # Base fields common to all asset types
        base_data = {
            'id': db.id,
            'type': db.type,
            'name': db.name,
            'desc': db.desc,
            'tags': db.tags or [],
            'image_url': db.image_url,
            'image_urls': db.image_urls,
            'video_urls': db.video_urls,
            'image_prompt': db.image_prompt,
            'generations': generations,
        }
        
        # Add type-specific fields from extra_data
        extra_data = db.extra_data or {}
        
        if db.type == 'character':
            return CharacterAsset(
                **base_data,
                age=extra_data.get('age'),
                gender=extra_data.get('gender'),
                role=extra_data.get('role'),
                emotion=extra_data.get('emotion'),
                appearance=extra_data.get('appearance'),
            )
        elif db.type == 'scene':
            return SceneAsset(
                **base_data,
                location=extra_data.get('location'),
                time_of_day=extra_data.get('time_of_day'),
                environment_type=extra_data.get('environment_type'),
                weather=extra_data.get('weather'),
                atmosphere=extra_data.get('atmosphere'),
            )
        elif db.type == 'prop':
            return PropAsset(
                **base_data,
                usage=extra_data.get('usage'),
            )
        else:
            return OtherAsset(**base_data)
    
    @staticmethod
    def to_entity(
        schema: CreateAssetRequest,
        project_id: str,
        asset_id: str = None
    ) -> AssetDB:
        """Convert CreateAssetRequest schema to AssetDB entity
        
        Args:
            schema: CreateAssetRequest from API
            project_id: Project ID this asset belongs to
            asset_id: Optional asset ID (generated if not provided)
            
        Returns:
            AssetDB entity for database storage
        """
        # 提取 type-specific fields into extra_data
        extra_data = {}
        
        if isinstance(schema, CreateCharacterAssetRequest):
            extra_data = {
                'age': schema.age,
                'gender': schema.gender,
                'role': schema.role,
                'appearance': schema.appearance,
            }
        elif isinstance(schema, CreateSceneAssetRequest):
            extra_data = {
                'location': schema.location,
                'time_of_day': schema.time_of_day,
                'atmosphere': schema.atmosphere,
            }
        elif isinstance(schema, CreatePropAssetRequest):
            extra_data = {
                'usage': schema.usage,
            }
        
        return AssetDB(
            id=asset_id or str(uuid.uuid4()),
            project_id=project_id,
            type=schema.type,
            name=schema.name,
            desc=schema.desc,
            tags=schema.tags or [],
            image_url=schema.image_url,
            image_urls=schema.image_urls,
            video_urls=schema.video_urls,
            image_prompt=schema.image_prompt,
            extra_data=extra_data,
            generations=[],
        )
    
    @staticmethod
    def update_entity(db: AssetDB, schema: UpdateAssetRequest) -> AssetDB:
        """Update AssetDB entity with data from UpdateAssetRequest schema
        
        Args:
            db: Existing AssetDB entity
            schema: UpdateAssetRequest with new data
            
        Returns:
            Updated AssetDB entity
        """
        # Update base fields
        if schema.name is not None:
            db.name = schema.name
        
        if schema.desc is not None:
            db.desc = schema.desc
        
        if schema.tags is not None:
            db.tags = schema.tags
        
        if schema.image_url is not None:
            db.image_url = schema.image_url
        
        if schema.image_urls is not None:
            db.image_urls = schema.image_urls
        
        if schema.video_urls is not None:
            db.video_urls = schema.video_urls
        
        if schema.image_prompt is not None:
            db.image_prompt = schema.image_prompt
        
        if schema.generations is not None:
            # Convert GenerationRecord objects to dicts
            db.generations = [gen.model_dump() for gen in schema.generations]
        
        # Update type-specific fields in extra_data
        extra_data = db.extra_data or {}
        
        if schema.age is not None:
            extra_data['age'] = schema.age
        
        if schema.role is not None:
            extra_data['role'] = schema.role
        
        if schema.appearance is not None:
            extra_data['appearance'] = schema.appearance
        
        if schema.location is not None:
            extra_data['location'] = schema.location
        
        if schema.time_of_day is not None:
            extra_data['time_of_day'] = schema.time_of_day
        
        if schema.atmosphere is not None:
            extra_data['atmosphere'] = schema.atmosphere
        
        if schema.usage is not None:
            extra_data['usage'] = schema.usage
        
        db.extra_data = extra_data
        
        return db
