import logging
from typing import Optional, List
from fastapi import APIRouter, Query, Depends
from sqlmodel import Session
from src.config.database import engine
from src.services.canvas_metadata_service import CanvasMetadataService
from src.models.schemas import (
    ResponseModel,
    CanvasMetadata,
    CreateGeneralCanvasRequest,
    UpdateCanvasMetadataRequest
)
from src.utils.errors import ResourceNotFoundException, BusinessException, ErrorCode

router = APIRouter(tags=["canvas_metadata"])
logger = logging.getLogger(__name__)


def get_session():
    """ 依赖 to get database session"""
    with Session(engine) as session:
        yield session


@router.get("/projects/{project_id}/canvases", response_model=ResponseModel)
async def list_project_canvases(
    project_id: str,
    canvas_type: Optional[str] = Query(None, description="Filter by type: general, asset, storyboard"),
    include_deleted: bool = Query(False, description="Include deleted canvases"),
    session: Session = Depends(get_session)
):
    """ 查询 all canvases for a project.
    
    Args:
        project_id: Project ID
        canvas_type: Optional filter by canvas type (general, asset, storyboard)
        include_deleted: Whether to include soft-deleted canvases
        
    Returns:
        List of canvas metadata
        
    Raises:
        BusinessException: Failed to list canvases
    """
    try:
        service = CanvasMetadataService(session)
        canvases = service.list_canvases(project_id, canvas_type, include_deleted)
        
        # 转换 to dict format
        canvas_data = [
            CanvasMetadata(
                id=c.id,
                projectId=c.project_id,
                canvasType=c.canvas_type,
                relatedEntityType=c.related_entity_type,
                relatedEntityId=c.related_entity_id,
                name=c.name,
                description=c.description,
                orderIndex=c.order_index,
                isPinned=c.is_pinned,
                tags=c.tags,
                nodeCount=c.node_count,
                lastAccessedAt=c.last_accessed_at,
                accessCount=c.access_count,
                createdAt=c.created_at,
                updatedAt=c.updated_at,
                deletedAt=c.deleted_at
            ).model_dump(by_alias=True)
            for c in canvases
        ]
        
        return ResponseModel(data=canvas_data)
    except Exception as e:
        logger.error(f"Failed to list canvases for project {project_id}: {e}", exc_info=True)
        raise BusinessException(
            ErrorCode.UNKNOWN_ERROR,
            "Failed to list canvases",
            {"project_id": project_id, "reason": str(e)}
        )


@router.get("/canvases/{canvas_id}/metadata", response_model=ResponseModel)
async def get_canvas_metadata(
    canvas_id: str,
    session: Session = Depends(get_session)
):
    """ Get canvas metadata by ID.
    
    Args:
        canvas_id: Canvas ID
        
    Returns:
        Canvas metadata
        
    Raises:
        ResourceNotFoundException: Canvas not found
        BusinessException: Failed to get canvas metadata
    """
    try:
        service = CanvasMetadataService(session)
        canvas = service.get_canvas(canvas_id)
        
        if not canvas:
            raise ResourceNotFoundException("canvas", canvas_id)
        
        # 更新 access statistics
        service.update_access_stats(canvas.id)
        
        # 转换 to response format
        canvas_data = CanvasMetadata(
            id=canvas.id,
            projectId=canvas.project_id,
            canvasType=canvas.canvas_type,
            relatedEntityType=canvas.related_entity_type,
            relatedEntityId=canvas.related_entity_id,
            name=canvas.name,
            description=canvas.description,
            orderIndex=canvas.order_index,
            isPinned=canvas.is_pinned,
            tags=canvas.tags,
            nodeCount=canvas.node_count,
            lastAccessedAt=canvas.last_accessed_at,
            accessCount=canvas.access_count,
            createdAt=canvas.created_at,
            updatedAt=canvas.updated_at,
            deletedAt=canvas.deleted_at
        ).model_dump(by_alias=True)
        
        return ResponseModel(data=canvas_data)
    except ResourceNotFoundException:
        raise
    except Exception as e:
        logger.error(f"Failed to get canvas metadata {canvas_id}: {e}", exc_info=True)
        raise BusinessException(
            ErrorCode.CANVAS_NOT_FOUND,
            "Failed to get canvas metadata",
            {"canvas_id": canvas_id, "reason": str(e)}
        )


@router.get("/assets/{asset_id}/canvas", response_model=ResponseModel)
async def get_asset_canvas(
    asset_id: str,
    session: Session = Depends(get_session)
):
    """ Get canvas associated with an asset.
    Automatically creates the canvas if it doesn't exist.
    
    Args:
        asset_id: Asset ID
        
    Returns:
        Canvas metadata
        
    Raises:
        ResourceNotFoundException: Asset not found
        BusinessException: Failed to get asset canvas
    """
    try:
        service = CanvasMetadataService(session)
        canvas = service.get_or_create_asset_canvas(asset_id)
        
        # 转换 to response format
        canvas_data = CanvasMetadata(
            id=canvas.id,
            projectId=canvas.project_id,
            canvasType=canvas.canvas_type,
            relatedEntityType=canvas.related_entity_type,
            relatedEntityId=canvas.related_entity_id,
            name=canvas.name,
            description=canvas.description,
            orderIndex=canvas.order_index,
            isPinned=canvas.is_pinned,
            tags=canvas.tags,
            nodeCount=canvas.node_count,
            lastAccessedAt=canvas.last_accessed_at,
            accessCount=canvas.access_count,
            createdAt=canvas.created_at,
            updatedAt=canvas.updated_at,
            deletedAt=canvas.deleted_at
        ).model_dump(by_alias=True)
        
        return ResponseModel(data=canvas_data)
    except ValueError as e:
        raise ResourceNotFoundException("asset", asset_id)
    except Exception as e:
        logger.error(f"Failed to get asset canvas {asset_id}: {e}", exc_info=True)
        raise BusinessException(
            ErrorCode.UNKNOWN_ERROR,
            "Failed to get asset canvas",
            {"asset_id": asset_id, "reason": str(e)}
        )


@router.get("/storyboards/{storyboard_id}/canvas", response_model=ResponseModel)
async def get_storyboard_canvas(
    storyboard_id: str,
    session: Session = Depends(get_session)
):
    """ Get canvas associated with a storyboard.
    Automatically creates the canvas if it doesn't exist.
    
    Args:
        storyboard_id: Storyboard ID
        
    Returns:
        Canvas metadata
        
    Raises:
        ResourceNotFoundException: Storyboard not found
        BusinessException: Failed to get storyboard canvas
    """
    try:
        service = CanvasMetadataService(session)
        canvas = service.get_or_create_storyboard_canvas(storyboard_id)
        
        # 转换 to response format
        canvas_data = CanvasMetadata(
            id=canvas.id,
            projectId=canvas.project_id,
            canvasType=canvas.canvas_type,
            relatedEntityType=canvas.related_entity_type,
            relatedEntityId=canvas.related_entity_id,
            name=canvas.name,
            description=canvas.description,
            orderIndex=canvas.order_index,
            isPinned=canvas.is_pinned,
            tags=canvas.tags,
            nodeCount=canvas.node_count,
            lastAccessedAt=canvas.last_accessed_at,
            accessCount=canvas.access_count,
            createdAt=canvas.created_at,
            updatedAt=canvas.updated_at,
            deletedAt=canvas.deleted_at
        ).model_dump(by_alias=True)
        
        return ResponseModel(data=canvas_data)
    except ValueError as e:
        raise ResourceNotFoundException("storyboard", storyboard_id)
    except Exception as e:
        logger.error(f"Failed to get storyboard canvas {storyboard_id}: {e}", exc_info=True)
        raise BusinessException(
            ErrorCode.UNKNOWN_ERROR,
            "Failed to get storyboard canvas",
            {"storyboard_id": storyboard_id, "reason": str(e)}
        )


@router.post("/projects/{project_id}/canvases", response_model=ResponseModel)
async def create_general_canvas(
    project_id: str,
    request: CreateGeneralCanvasRequest,
    session: Session = Depends(get_session)
):
    """ Create a new general canvas for a project.
    
    Args:
        project_id: Project ID
        request: Canvas creation request with name and optional description
        
    Returns:
        Created canvas metadata
        
    Raises:
        BusinessException: Failed to create canvas
    """
    try:
        service = CanvasMetadataService(session)
        canvas = service.create_general_canvas(
            project_id=project_id,
            name=request.name,
            description=request.description
        )
        
        # 转换 to response format
        canvas_data = CanvasMetadata(
            id=canvas.id,
            projectId=canvas.project_id,
            canvasType=canvas.canvas_type,
            relatedEntityType=canvas.related_entity_type,
            relatedEntityId=canvas.related_entity_id,
            name=canvas.name,
            description=canvas.description,
            orderIndex=canvas.order_index,
            isPinned=canvas.is_pinned,
            tags=canvas.tags,
            nodeCount=canvas.node_count,
            lastAccessedAt=canvas.last_accessed_at,
            accessCount=canvas.access_count,
            createdAt=canvas.created_at,
            updatedAt=canvas.updated_at,
            deletedAt=canvas.deleted_at
        ).model_dump(by_alias=True)
        
        return ResponseModel(data=canvas_data)
    except Exception as e:
        logger.error(f"Failed to create general canvas for project {project_id}: {e}", exc_info=True)
        raise BusinessException(
            ErrorCode.UNKNOWN_ERROR,
            "Failed to create canvas",
            {"project_id": project_id, "reason": str(e)}
        )


@router.put("/canvases/{canvas_id}/metadata", response_model=ResponseModel)
async def update_canvas_metadata(
    canvas_id: str,
    request: UpdateCanvasMetadataRequest,
    session: Session = Depends(get_session)
):
    """ 更新 canvas metadata.
    
    Args:
        canvas_id: Canvas ID
        request: Update request with optional fields
        
    Returns:
        Updated canvas metadata
        
    Raises:
        ResourceNotFoundException: Canvas not found
        BusinessException: Failed to update canvas
    """
    try:
        service = CanvasMetadataService(session)
        
        # 转换 request to dict, excluding unset fields
        updates = request.model_dump(exclude_unset=True, by_alias=False)
        
        canvas = service.update_canvas(canvas_id, updates)
        
        if not canvas:
            raise ResourceNotFoundException("canvas", canvas_id)
        
        # 转换 to response format
        canvas_data = CanvasMetadata(
            id=canvas.id,
            projectId=canvas.project_id,
            canvasType=canvas.canvas_type,
            relatedEntityType=canvas.related_entity_type,
            relatedEntityId=canvas.related_entity_id,
            name=canvas.name,
            description=canvas.description,
            orderIndex=canvas.order_index,
            isPinned=canvas.is_pinned,
            tags=canvas.tags,
            nodeCount=canvas.node_count,
            lastAccessedAt=canvas.last_accessed_at,
            accessCount=canvas.access_count,
            createdAt=canvas.created_at,
            updatedAt=canvas.updated_at,
            deletedAt=canvas.deleted_at
        ).model_dump(by_alias=True)
        
        return ResponseModel(data=canvas_data)
    except ResourceNotFoundException:
        raise
    except Exception as e:
        logger.error(f"Failed to update canvas metadata {canvas_id}: {e}", exc_info=True)
        raise BusinessException(
            ErrorCode.UNKNOWN_ERROR,
            "Failed to update canvas",
            {"canvas_id": canvas_id, "reason": str(e)}
        )


@router.put("/projects/{project_id}/canvases/reorder", response_model=ResponseModel)
async def reorder_canvases(
    project_id: str,
    canvas_orders: List[dict],
    session: Session = Depends(get_session)
):
    """ 批处理 update canvas order indices.
    
    Args:
        project_id: Project ID
        canvas_orders: List of {id, order_index} objects
        
    Returns:
        Success confirmation
        
    Raises:
        BusinessException: Failed to reorder canvases
    """
    try:
        service = CanvasMetadataService(session)
        service.reorder_canvases(canvas_orders)
        
        return ResponseModel(data={"updated": True})
    except Exception as e:
        logger.error(f"Failed to reorder canvases for project {project_id}: {e}", exc_info=True)
        raise BusinessException(
            ErrorCode.UNKNOWN_ERROR,
            "Failed to reorder canvases",
            {"project_id": project_id, "reason": str(e)}
        )


@router.delete("/canvases/{canvas_id}", response_model=ResponseModel)
async def delete_canvas(
    canvas_id: str,
    hard_delete: bool = Query(False, description="Permanently delete (true) or soft delete (false)"),
    session: Session = Depends(get_session)
):
    """ 删除 a canvas.
    
    Args:
        canvas_id: Canvas ID
        hard_delete: If true, permanently delete; if false, soft delete
        
    Returns:
        Success confirmation
        
    Raises:
        BusinessException: Failed to delete canvas
    """
    try:
        service = CanvasMetadataService(session)
        service.delete_canvas(canvas_id, hard_delete)
        
        return ResponseModel(data={"deleted": True})
    except Exception as e:
        logger.error(f"Failed to delete canvas {canvas_id}: {e}", exc_info=True)
        raise BusinessException(
            ErrorCode.UNKNOWN_ERROR,
            "Failed to delete canvas",
            {"canvas_id": canvas_id, "hard_delete": hard_delete, "reason": str(e)}
        )
