import logging
from typing import Any, Optional

from app.auth import AuthenticatedUser, get_current_user
from app.dependencies import (
    get_asset_library_repository,
    get_asset_repository,
    get_project_repository,
)
from app.schemas.asset_diagnosis import AssetGapItem, AssetSmartViewItem, ProjectAssetDiagnosisResponse
from fastapi import APIRouter, Depends, HTTPException, Query

from packages.domain import Asset, AssetLibraryKind, AssetStatus

logger = logging.getLogger(__name__)

router = APIRouter()


def _asset_kind(asset: Asset) -> str:
    if asset.mime_type.startswith("video"):
        return "video"
    if asset.mime_type.startswith("audio"):
        return "voice"
    if asset.mime_type.startswith("image"):
        return "image"
    return asset.mime_type.split("/", 1)[0]


def _readiness_label(score: int) -> str:
    if score >= 80:
        return "素材充足"
    if score >= 60:
        return "基本可生成"
    if score >= 40:
        return "需要补素材"
    return "暂不建议生成"


def _build_diagnosis(project_id: str, assets: list[Asset]) -> ProjectAssetDiagnosisResponse:
    ready_assets = [asset for asset in assets if asset.status == AssetStatus.READY]
    video_assets = [asset for asset in ready_assets if _asset_kind(asset) == AssetLibraryKind.VIDEO]
    image_assets = [asset for asset in ready_assets if _asset_kind(asset) == AssetLibraryKind.IMAGE]
    voice_assets = [asset for asset in ready_assets if _asset_kind(asset) == AssetLibraryKind.VOICE]
    problem_assets = [
        asset for asset in assets if asset.status in {AssetStatus.ERROR, AssetStatus.UPLOADING, AssetStatus.PROCESSING}
    ]
    unclassified_assets = [
        asset for asset in ready_assets if asset.classification_status.value in {"pending", "failed"}
    ]
    risky_assets = [
        asset
        for asset in ready_assets
        if (asset.quality_score is not None and asset.quality_score < 60)
        or asset.metadata.get("review_status") == "rejected"
        or asset.status == AssetStatus.ERROR
    ]
    used_assets = [asset for asset in ready_assets if int(asset.metadata.get("generation_use_count") or 0) > 0]
    unused_assets = [asset for asset in ready_assets if int(asset.metadata.get("generation_use_count") or 0) == 0]
    pending_review_assets = [asset for asset in ready_assets if asset.metadata.get("review_status") == "pending_review"]
    total_duration = round(sum(float(asset.duration or 0) for asset in video_assets), 2)
    estimated_video_count = max(
        0, min(len(video_assets), int(total_duration // 5) if total_duration else len(video_assets))
    )

    score = 20
    if video_assets:
        score += 30
    if len(video_assets) >= 3:
        score += 15
    if total_duration >= 15:
        score += 15
    if image_assets:
        score += 5
    if voice_assets:
        score += 5
    if not problem_assets:
        score += 10
    score = max(0, min(100, score - min(25, len(risky_assets) * 5)))

    gaps: list[AssetGapItem] = []
    if not video_assets:
        gaps.append(
            AssetGapItem(
                key="missing_video",
                severity="critical",
                message="缺少可用于生成的视频素材",
                recommendation="至少上传 1 个已导入完成的视频素材；建议上传 3 个以上，生成效果更稳定。",
            )
        )
    elif len(video_assets) < 3:
        gaps.append(
            AssetGapItem(
                key="low_video_count",
                severity="warning",
                message="视频素材数量偏少",
                recommendation="建议补充到 3 个以上视频素材，方便生成更多候选成片。",
            )
        )
    if total_duration and total_duration < 15:
        gaps.append(
            AssetGapItem(
                key="short_video_duration",
                severity="warning",
                message="可用视频总时长偏短",
                recommendation="建议补充更多原始视频，至少达到 15 秒以上。",
            )
        )
    if not voice_assets:
        gaps.append(
            AssetGapItem(
                key="missing_voice",
                severity="info",
                message="暂未配置配音素材",
                recommendation="如果本项目需要口播/旁白，请上传配音素材；纯画面生成可暂时忽略。",
            )
        )
    if problem_assets:
        gaps.append(
            AssetGapItem(
                key="not_ready_assets",
                severity="warning",
                message=f"有 {len(problem_assets)} 个素材尚未 ready",
                recommendation="等待导入完成或删除失败素材后再生成。",
            )
        )
    if risky_assets:
        gaps.append(
            AssetGapItem(
                key="low_quality_assets",
                severity="warning",
                message=f"有 {len(risky_assets)} 个素材质量分偏低",
                recommendation="优先使用清晰、稳定、时长充足的视频素材。",
            )
        )

    smart_views = [
        AssetSmartViewItem(
            key="recommended", label="推荐素材", count=len(video_assets), description="已导入完成、可参与生成的视频素材"
        ),
        AssetSmartViewItem(
            key="needs_attention",
            label="慎用素材",
            count=len(problem_assets) + len(risky_assets),
            description="导入未完成、失败或质量分偏低的素材",
        ),
        AssetSmartViewItem(
            key="high_risk", label="高风险素材", count=len(risky_assets), description="质量分偏低或复核拒绝的素材"
        ),
        AssetSmartViewItem(
            key="unclassified",
            label="未分类素材",
            count=len(unclassified_assets),
            description="尚未完成分类或分类失败的 ready 素材",
        ),
        AssetSmartViewItem(
            key="recent",
            label="最近上传",
            count=min(len(assets), 10),
            description="最近进入素材库的素材，可用于快速复核",
        ),
        AssetSmartViewItem(
            key="unused", label="未使用素材", count=len(unused_assets), description="尚未参与生成的 ready 素材"
        ),
        AssetSmartViewItem(key="used", label="已使用素材", count=len(used_assets), description="已经参与过生成的素材"),
        AssetSmartViewItem(
            key="pending_review",
            label="待复核素材",
            count=len(pending_review_assets),
            description="生成后待人工复核的素材",
        ),
        AssetSmartViewItem(
            key="voice", label="配音素材", count=len(voice_assets), description="可用于后续配音/旁白工作流的素材"
        ),
    ]

    return ProjectAssetDiagnosisResponse(
        project_id=project_id,
        readiness_score=score,
        readiness_label=_readiness_label(score),
        total_assets=len(assets),
        ready_assets=len(ready_assets),
        video_assets=len(video_assets),
        image_assets=len(image_assets),
        voice_assets=len(voice_assets),
        total_duration_seconds=total_duration,
        estimated_video_count=estimated_video_count,
        used_assets=len(used_assets),
        unused_assets=len(unused_assets),
        pending_review_assets=len(pending_review_assets),
        smart_views=smart_views,
        gaps=gaps,
    )


def _build_single_asset_diagnosis(project_id: str, asset: Asset) -> ProjectAssetDiagnosisResponse:
    """为单个素材构建诊断结果"""
    kind = _asset_kind(asset)
    is_ready = asset.status == AssetStatus.READY
    is_problem = asset.status in {AssetStatus.ERROR, AssetStatus.UPLOADING, AssetStatus.PROCESSING}
    is_risky = is_ready and (
        (asset.quality_score is not None and asset.quality_score < 60)
        or asset.metadata.get("review_status") == "rejected"
        or asset.status == AssetStatus.ERROR
    )
    is_unclassified = is_ready and asset.classification_status.value in {"pending", "failed"}

    # 单素材评分
    score = 0
    if is_ready:
        score = 60
        if kind == "video":
            score += 20
        if asset.duration and asset.duration >= 5:
            score += 10
        if asset.quality_score and asset.quality_score >= 60:
            score += 10
    if is_problem:
        score = max(score - 30, 0)
    if is_risky:
        score = max(score - 20, 0)
    score = max(0, min(100, score))

    gaps: list[AssetGapItem] = []
    if not is_ready:
        gaps.append(
            AssetGapItem(
                key="asset_not_ready",
                severity="critical",
                message=f"素材状态为 {asset.status.value}，尚未就绪",
                recommendation="等待素材导入完成后再使用。",
            )
        )
    if is_risky:
        gaps.append(
            AssetGapItem(
                key="asset_low_quality",
                severity="warning",
                message="素材质量分偏低或已被拒绝",
                recommendation="建议使用更清晰、稳定的素材替代。",
            )
        )
    if is_unclassified:
        gaps.append(
            AssetGapItem(
                key="asset_unclassified",
                severity="info",
                message="素材尚未完成分类",
                recommendation="等待分类完成或手动检查素材类型。",
            )
        )
    if kind == "video" and (asset.duration is None or asset.duration < 5):
        gaps.append(
            AssetGapItem(
                key="short_video",
                severity="warning",
                message="视频时长偏短",
                recommendation="建议使用时长 5 秒以上的视频素材。",
            )
        )

    used_count = int(asset.metadata.get("generation_use_count") or 0)
    smart_views = [
        AssetSmartViewItem(
            key="asset_info",
            label="素材信息",
            count=1,
            description=f"类型: {kind}，状态: {asset.status.value}",
        ),
        AssetSmartViewItem(
            key="asset_quality",
            label="质量评分",
            count=int(asset.quality_score or 0),
            description=f"质量分: {asset.quality_score or '未评分'}",
        ),
        AssetSmartViewItem(
            key="asset_usage",
            label="使用次数",
            count=used_count,
            description=f"参与生成 {used_count} 次",
        ),
    ]

    video_count = 1 if kind == "video" and is_ready else 0
    image_count = 1 if kind == "image" and is_ready else 0
    voice_count = 1 if kind == "voice" and is_ready else 0
    total_duration = round(float(asset.duration or 0), 2) if kind == "video" else 0.0

    return ProjectAssetDiagnosisResponse(
        project_id=project_id,
        readiness_score=score,
        readiness_label=_readiness_label(score),
        total_assets=1,
        ready_assets=1 if is_ready else 0,
        video_assets=video_count,
        image_assets=image_count,
        voice_assets=voice_count,
        total_duration_seconds=total_duration,
        estimated_video_count=1 if video_count and total_duration >= 5 else 0,
        used_assets=1 if used_count > 0 else 0,
        unused_assets=1 if used_count == 0 and is_ready else 0,
        pending_review_assets=1 if asset.metadata.get("review_status") == "pending_review" else 0,
        smart_views=smart_views,
        gaps=gaps,
    )


@router.get("/projects/{project_id}/asset-diagnosis", response_model=ProjectAssetDiagnosisResponse)
def get_project_asset_diagnosis(
    project_id: str,
    asset_id: Optional[str] = Query(None),
    authenticated_user: AuthenticatedUser = Depends(get_current_user),
    project_repository: Any = Depends(get_project_repository),
    asset_library_repository: Any = Depends(get_asset_library_repository),
    asset_repository: Any = Depends(get_asset_repository),
) -> ProjectAssetDiagnosisResponse:
    try:
        project = project_repository.find_by_id(project_id)
        if project is None:
            raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
        if not project.can_access(authenticated_user.user.id):
            raise HTTPException(status_code=403, detail="Access denied to project")

        # 单素材诊断模式
        if asset_id:
            asset = asset_repository.get(asset_id)
            if asset is None:
                raise HTTPException(status_code=404, detail=f"Asset {asset_id} not found")
            if asset.project_id != project_id:
                raise HTTPException(status_code=403, detail="Asset does not belong to this project")
            return _build_single_asset_diagnosis(project_id, asset)

        libraries = asset_library_repository.find_by_project(project_id)
        assets: list[Asset] = []
        for library in libraries:
            assets.extend(asset_repository.list_by_library(library.id))
    except HTTPException:
        raise
    except Exception:
        logger.exception("素材诊断查询失败: project_id=%s", project_id)
        # 返回空诊断结果，避免 500
        return _build_diagnosis(project_id, [])

    return _build_diagnosis(project_id, assets)
