from typing import Annotated, Literal

from pydantic import BaseModel, ConfigDict, Field

from app.schemas.common import NaiveDatetimeOptional


class GenerationAIReference(BaseModel):
    """AI生成任务参考素材。"""

    model_config = ConfigDict(
        json_schema_extra={
            "example": {
                "url": "https://example.com/reference.png",
                "type": "image",
                "name": "参考图.png",
            }
        }
    )

    url: str = Field(
        ...,
        description="参考素材地址，可以是图片地址或视频地址",
        examples=["https://example.com/reference.png"],
    )
    type: str = Field(
        ...,
        description="参考素材类型：image=图片，video=视频",
        examples=["image"],
    )
    name: str | None = Field(
        None,
        description="参考素材名称，前端展示用，可为空",
        examples=["参考图.png"],
    )


class GenerationAITaskCreate(BaseModel):
    """创建AI图片/视频生成任务请求体。"""

    model_config = ConfigDict(
        json_schema_extra={
            "examples": [
                {
                    "project_id": None,
                    "gen_type": "image",
                    "original_prompt": "生成一张赛博朋克风格的城市夜景",
                    "engine_id": None,
                    "media_references": [
                        {
                            "url": "https://example.com/reference.png",
                            "type": "image",
                            "name": "参考图.png",
                        }
                    ],
                    "idempotency_key": "frontend-submit-uuid-001",
                    "image_size": "2K",
                    "image_proportion": "1:1",
                    "image_px": "2048x2048",
                    "duration": None,
                    "aspect_ratio": None,
                    "resolution": None,
                },
                {
                    "project_id": None,
                    "gen_type": "video",
                    "original_prompt": "生成一段海边日落的电影感视频",
                    "engine_id": None,
                    "media_references": None,
                    "idempotency_key": "frontend-submit-uuid-002",
                    "image_size": None,
                    "image_proportion": None,
                    "image_px": None,
                    "duration": 4,
                    "aspect_ratio": "16:9",
                    "resolution": "480p",
                },
            ]
        }
    )

    # 新 chat 生成任务不绑定 project_id。为了兼容旧前端误传，保留可选字段但后端不使用。
    project_id: str | None = Field(
        None,
        description="兼容旧前端字段。当前 /generation-ai 任务不绑定项目，后端不使用该字段，可传 null 或不传",
        examples=[None],
    )
    gen_type: str = Field(
        ...,
        description="生成类型：image=图片生成，video=视频生成",
        examples=["image"],
    )
    original_prompt: str = Field(
        ...,
        min_length=1,
        max_length=5000,
        description="用户原始提示词，不能为空，最长5000字符",
        examples=["生成一张赛博朋克风格的城市夜景"],
    )
    engine_id: str | None = Field(
        None,
        description="图片/视频引擎ID；为空则使用当前激活且优先级最高的引擎",
        examples=[None],
    )
    media_references: list[GenerationAIReference] | None = Field(
        None,
        description="参考素材列表。可以传图片/视频参考素材；为空表示不使用参考素材",
    )
    idempotency_key: str | None = Field(
        None,
        max_length=64,
        description=(
            "幂等键，用于防止前端重复提交、网络重试导致重复创建任务和重复扣费。"
            "同一用户、同一 idempotency_key、同一 generation_mode 下重复请求会返回已有任务。"
            "建议前端每次点击生成时生成 UUID；同一次请求失败重试时复用同一个 UUID。"
        ),
        examples=["frontend-submit-uuid-001"],
    )

    # image params
    image_size: str | None = Field(
        None,
        description="图片分辨率档位，例如：1K、2K。仅图片生成或视频首帧参数需要使用；为空则使用引擎默认值",
        examples=["2K"],
    )
    image_proportion: str | None = Field(
        None,
        description="图片比例，例如：1:1、16:9、9:16。仅图片生成或视频首帧参数需要使用；为空则使用默认值",
        examples=["1:1"],
    )
    image_px: str | None = Field(
        None,
        description="图片像素尺寸，例如：2048x2048。为空时后端根据 image_size 和 image_proportion 自动匹配",
        examples=["2048x2048"],
    )

    # video params
    duration: int | None = Field(
        None,
        description="视频时长，单位秒。仅视频生成使用；为空则使用默认时长",
        examples=[4],
    )
    aspect_ratio: str | None = Field(
        None,
        description="视频比例，例如：16:9、9:16、1:1。仅视频生成使用；为空则使用默认比例",
        examples=["16:9"],
    )
    resolution: str | None = Field(
        None,
        description="视频分辨率，例如：480p、720p、1080p。仅视频生成使用；为空则使用默认分辨率",
        examples=["480p"],
    )




class GenerationAIImageEngineOptionOut(BaseModel):
    """AI图片生成可用引擎响应项。"""

    id: str = Field(..., description="图片引擎ID，创建图片任务时传入 engine_id")
    name: str = Field(..., description="图片引擎名称，前端展示用")
    provider: str = Field(..., description="服务商标识，例如 ark")
    model_name: str | None = Field(None, description="服务商模型名称")
    supported_models: list[str] = Field(default_factory=list, description="该图片引擎支持的模型名称列表")
    supported_sizes: dict = Field(
        default_factory=dict,
        description="支持的图片尺寸映射。第一层为分辨率档位，例如 2K/4K；第二层为画布比例，例如 1:1/16:9；值为像素尺寸",
    )
    default_size: str | None = Field(None, description="默认图片分辨率档位，例如 2K")
    priority: int = Field(0, description="引擎优先级，数值越大越优先")


class GenerationAIVideoEngineOptionOut(BaseModel):
    """AI视频生成可用引擎响应项。"""

    id: str = Field(..., description="视频引擎ID，创建视频任务时传入 engine_id")
    name: str = Field(..., description="视频引擎名称，前端展示用")
    provider: str = Field(..., description="服务商标识，例如 ark")
    model_name: str | None = Field(None, description="服务商模型名称")
    supported_ratios: list[str] = Field(default_factory=list, description="支持的视频画面比例，例如 16:9、9:16、1:1")
    supported_resolutions: list[str] = Field(default_factory=list, description="支持的视频分辨率，例如 480p、720p、1080p")
    supported_durations: list[int] = Field(default_factory=list, description="支持的视频时长列表，单位秒")
    max_duration: int | None = Field(None, description="最大视频时长，单位秒")
    priority: int = Field(0, description="引擎优先级，数值越大越优先")


class GenerationAIEngineGroupOut(BaseModel):
    """AI图片/视频引擎分组。"""

    image: list[GenerationAIImageEngineOptionOut] = Field(
        default_factory=list,
        description="当前启用的图片生成引擎列表",
    )
    video: list[GenerationAIVideoEngineOptionOut] = Field(
        default_factory=list,
        description="当前启用的视频生成引擎列表",
    )


class GenerationAIEngineOptionsOut(BaseModel):
    """AI图片/视频生成引擎列表响应体。"""

    model_config = ConfigDict(
        json_schema_extra={
            "example": {
                "engine": {
                    "image": [
                        {
                            "id": "image_engine_xxx",
                            "name": "豆包文生图",
                            "provider": "ark",
                            "model_name": "doubao-seedream-5-0-260128",
                            "supported_models": ["doubao-seedream-5-0-260128"],
                            "supported_sizes": {
                                "2K": {
                                    "1:1": "2048x2048",
                                    "16:9": "2560x1440",
                                }
                            },
                            "default_size": "2K",
                            "priority": 10,
                        }
                    ],
                    "video": [
                        {
                            "id": "video_engine_xxx",
                            "name": "Seedance 2.0",
                            "provider": "ark",
                            "model_name": "doubao-seedance-2-0-260128",
                            "supported_ratios": ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"],
                            "supported_resolutions": ["480p", "720p", "1080p"],
                            "supported_durations": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
                            "max_duration": 15,
                            "priority": 10,
                        }
                    ],
                }
            }
        }
    )

    engine: GenerationAIEngineGroupOut = Field(..., description="图片/视频可用引擎分组")


class GenerationAITaskOut(BaseModel):
    """AI生成任务详情响应体。"""

    model_config = ConfigDict(
        json_schema_extra={
            "example": {
                "id": "0019e0a44895b6d837d",
                "source_type": "chat_task",
                "user_id": None,
                "user_name": None,
                "project_id": None,
                "generated_resource_id": "generated_resource_xxx",
                "gen_type": "image",
                "generation_mode": "chatapi_async",
                "pipeline_stage": "done",
                "status": "completed",
                "original_prompt": "生成一张赛博朋克风格的城市夜景",
                "optimized_prompt": None,
                "duration": None,
                "aspect_ratio": None,
                "resolution": None,
                "image_size": "2K",
                "image_proportion": "1:1",
                "image_px": "2048x2048",
                "media_references": None,
                "provider_task_id": "provider_task_xxx",
                "seedance_task_id": "provider_task_xxx",
                "remote_result_url": None,
                "image_url": "https://example.com/result.png",
                "video_url": None,
                "video_cover_url": None,
                "engine_id": "engine_xxx",
                "engine_snapshot": {
                    "engine_type": "image",
                    "id": "engine_xxx",
                    "name": "图片生成引擎",
                    "provider": "provider_name",
                    "model_name": "model_name",
                    "supported_models": [],
                    "default_size": "2K",
                    "selected_size": "2K",
                    "selected_proportion": "1:1",
                    "selected_px": "2048x2048",
                },
                "credits_cost": 10.0,
                "text_credits_cost": 0.0,
                "text_tokens_used": 0,
                "image_tokens_used": 0,
                "video_tokens_used": 0,
                "retry_count": 0,
                "poll_count": 3,
                "error_message": None,
                "created_at": "2026-05-27T10:12:00",
                "generated_at": "2026-05-27T10:15:30",
            }
        }
    )

    id: str = Field(..., description="生成任务ID")
    source_type: Literal["chat_task"] = Field(
        "chat_task",
        description="历史记录来源。ChatGenerationTask 新任务历史固定为 chat_task",
    )
    user_id: str | None = Field(
        None,
        description="用户ID，管理后台调用存在对应值，通常为 null",
    )
    user_name: str | None = Field(
        None,
        description="用户名称，管理后台调用存在对应值，通常为 null",
    )
    project_id: str | None = Field(
        None,
        description="项目ID。当前 /generation-ai 任务不绑定项目，通常为 null",
    )
    generated_resource_id: str | None = Field(
        None,
        description="关联的生成资源账本ID，来源于 generated_resources.id；历史脏数据可能为空",
    )
    file_name: str | None = Field(None, description="文件名，来源于 generated_resources.file_name")
    gen_type: str = Field(..., description="生成类型：image=图片，video=视频")
    generation_mode: str | None = Field(
        None,
        description="生成模式。当前异步Chat生成任务一般为 chatapi_async",
    )
    pipeline_stage: str | None = Field(
        None,
        description=(
            "任务流水线阶段，例如：queued=已入队，creating_provider_task=创建第三方任务中，"
            "waiting_remote=等待第三方生成，result_ready=远程结果已就绪，downloading=下载中，done=完成"
        ),
    )
    status: str = Field(
        ...,
        description="任务状态，例如：generating=生成中，completed=已完成，failed=失败",
    )
    original_prompt: str = Field(..., description="用户原始提示词")
    optimized_prompt: str | None = Field(None, description="优化后的提示词，可能为空")
    duration: int | None = Field(None, description="视频时长，单位秒。图片任务通常为空")
    aspect_ratio: str | None = Field(None, description="视频比例，例如 16:9。图片任务通常为空")
    resolution: str | None = Field(None, description="视频分辨率，例如 480p。图片任务通常为空")
    image_size: str | None = Field(None, description="图片分辨率档位，例如 2K")
    image_proportion: str | None = Field(None, description="图片比例，例如 1:1")
    image_px: str | None = Field(None, description="图片像素尺寸，例如 2048x2048")
    media_references: list[dict] | None = Field(
        None,
        description="参考素材列表。由创建任务时传入的 media_references 转换而来",
    )
    provider_task_id: str | None = Field(None, description="第三方服务商任务ID")
    seedance_task_id: str | None = Field(
        None,
        description="兼容旧前端/旧服务命名的第三方任务ID字段",
    )
    remote_result_url: str | None = Field(
        None,
        description="第三方远程结果地址。当前接口可能隐藏或为空，最终展示优先使用 image_url/video_url",
    )
    image_url: str | None = Field(None, description="最终图片地址。图片任务完成后通常有值")
    video_url: str | None = Field(None, description="最终视频地址。视频任务完成后通常有值")
    video_cover_url: str | None = Field(None, description="视频封面图片地址。视频任务完成且封面截帧成功后通常有值")
    engine_id: str | None = Field(None, description="本次任务使用的生成引擎ID")
    engine_snapshot: dict | None = Field(
        None,
        description="生成任务创建时的引擎快照，用于前端展示当时使用的模型、比例、尺寸等信息",
    )
    credits_cost: float = Field(0.0, description="本次任务总消耗积分")
    text_credits_cost: float = Field(0.0, description="文本优化或文本处理消耗积分")
    text_tokens_used: int = Field(0, description="文本 token 使用量")
    image_tokens_used: int = Field(0, description="图片 token 使用量")
    video_tokens_used: int = Field(0, description="视频 token 使用量")
    retry_count: int = Field(0, description="任务重试次数")
    poll_count: int = Field(0, description="轮询第三方任务状态次数")
    error_message: str | None = Field(None, description="错误信息。成功任务一般为 null")
    created_at: NaiveDatetimeOptional = Field(None, description="任务创建时间")
    generated_at: NaiveDatetimeOptional = Field(None, description="任务生成完成时间")


class GenerationAITaskListOut(BaseModel):
    """AI生成任务列表响应体。"""

    model_config = ConfigDict(
        json_schema_extra={
            "example": {
                "total": 1,
                "items": [
                    {
                        "id": "0019e0a44895b6d837d",
                        "source_type": "chat_task",
                        "user_id": None,
                        "user_name": None,
                        "project_id": None,
                        "gen_type": "image",
                        "generation_mode": "chatapi_async",
                        "pipeline_stage": "done",
                        "status": "completed",
                        "original_prompt": "生成一张赛博朋克风格的城市夜景",
                        "optimized_prompt": None,
                        "duration": None,
                        "aspect_ratio": None,
                        "resolution": None,
                        "image_size": "2K",
                        "image_proportion": "1:1",
                        "image_px": "2048x2048",
                        "media_references": None,
                        "provider_task_id": "provider_task_xxx",
                        "seedance_task_id": "provider_task_xxx",
                        "remote_result_url": None,
                        "image_url": "https://example.com/result.png",
                        "video_url": None,
                        "video_cover_url": None,
                        "engine_id": "engine_xxx",
                        "engine_snapshot": {},
                        "credits_cost": 10.0,
                        "text_credits_cost": 0.0,
                        "text_tokens_used": 0,
                        "image_tokens_used": 0,
                        "video_tokens_used": 0,
                        "retry_count": 0,
                        "poll_count": 3,
                        "error_message": None,
                        "created_at": "2026-05-27T10:12:00",
                        "generated_at": "2026-05-27T10:15:30",
                    }
                ],
            }
        }
    )

    total: int = Field(..., description="符合筛选条件的任务总数")
    items: list[GenerationAITaskOut] = Field(
        default_factory=list,
        description="当前分页的任务列表",
    )




class GenerationAITaskDeleteOut(BaseModel):
    """AI生成任务删除响应体。"""

    model_config = ConfigDict(
        json_schema_extra={
            "example": {
                "message": "任务已删除",
                "task_id": "0019e0a44895b6d837d",
                "deleted": True,
                "freed_size_bytes": 123456,
            }
        }
    )

    message: str = Field(..., description="操作结果提示信息")
    task_id: str = Field(..., description="被软删除的AI生成任务ID")
    deleted: bool = Field(..., description="是否已完成软删除")
    freed_size_bytes: int = Field(0, description="本次软删联动释放的有效资源空间字节数")


class GenerationAIRetryOut(BaseModel):
    """AI生成任务重试响应体。"""

    model_config = ConfigDict(
        json_schema_extra={
            "example": {
                "id": "0019e0a44895b6d837d",
                "status": "generating",
                "pipeline_stage": "queued",
                "message": "任务已重新投递",
            }
        }
    )

    id: str = Field(..., description="被重试的任务ID")
    status: str = Field(..., description="重试后的任务状态")
    pipeline_stage: str | None = Field(None, description="重试后的任务流水线阶段")
    message: str = Field(..., description="操作结果提示信息")


class GenerationAIRecordHistoryItemOut(BaseModel):
    """旧 generation_records 历史记录详情响应体。"""

    model_config = ConfigDict(
        json_schema_extra={
            "example": {
                "id": "0019e0a44895b6d837d",
                "source_type": "generation_record",
                "project_id": "project_xxx",
                "project_name": "默认项目",
                "generated_resource_id": "generated_resource_xxx",
                "gen_type": "image",
                "generation_mode": "generation_record",
                "pipeline_stage": None,
                "status": "completed",
                "original_prompt": "生成一张赛博朋克风格的城市夜景",
                "optimized_prompt": "赛博朋克城市夜景，霓虹灯，电影感，高细节",
                "duration": None,
                "aspect_ratio": None,
                "resolution": None,
                "image_size": "2K",
                "image_proportion": "1:1",
                "image_px": "2048x2048",
                "references": None,
                "media_references": None,
                "provider_task_id": "provider_task_xxx",
                "seedance_task_id": "provider_task_xxx",
                "remote_result_url": None,
                "image_url": "https://example.com/result.png",
                "video_url": None,
                "video_cover_url": None,
                "engine_id": None,
                "engine_snapshot": None,
                "credits_cost": 10.0,
                "text_credits_cost": 1.0,
                "text_tokens_used": 100,
                "image_tokens_used": 0,
                "video_tokens_used": 0,
                "retry_count": 0,
                "poll_count": 0,
                "error_message": None,
                "created_at": "2026-05-27T10:12:00",
                "generated_at": "2026-05-27T10:15:30",
            }
        }
    )

    id: str = Field(..., description="旧生成记录ID")
    source_type: Literal["generation_record"] = Field(
        "generation_record",
        description="历史记录来源固定为 generation_record，用于和 chat_task 历史区分",
    )
    project_id: str | None = Field(None, description="旧项目ID，来源于 generation_records.project_id")
    project_name: str | None = Field(None, description="旧项目名称，来源于 projects.name；项目不存在时为空")
    generated_resource_id: str | None = Field(
        None,
        description="关联的生成资源账本ID，来源于 generated_resources.id；历史脏数据可能为空",
    )
    file_name: str | None = Field(None, description="文件名，来源于 generated_resources.file_name")
    gen_type: str = Field(..., description="生成类型：image=图片，video=视频")
    generation_mode: str | None = Field(
        "generation_record",
        description="兼容新历史结构的生成模式字段。旧表历史固定返回 generation_record",
    )
    pipeline_stage: str | None = Field(
        None,
        description="兼容新历史结构的流水线阶段字段。旧 generation_records 无该字段，固定为 null",
    )
    status: str = Field(..., description="记录状态，例如 completed=已完成，failed=失败")
    original_prompt: str = Field(..., description="用户原始提示词")
    optimized_prompt: str | None = Field(None, description="优化后的提示词，可能为空")
    duration: int | None = Field(None, description="视频时长，单位秒。图片记录通常为空")
    aspect_ratio: str | None = Field(None, description="视频比例，例如 16:9。图片记录通常为空")
    resolution: str | None = Field(None, description="视频分辨率，例如 480p。图片记录通常为空")
    image_size: str | None = Field(None, description="图片分辨率档位，例如 2K")
    image_proportion: str | None = Field(None, description="图片比例，例如 1:1")
    image_px: str | None = Field(None, description="图片像素尺寸，例如 2048x2048")
    references: list[dict] | None = Field(
        None,
        description="旧接口字段名，来源于 generation_records.media_references 解析后的参考素材列表",
    )
    media_references: list[dict] | None = Field(
        None,
        description="兼容新历史结构字段名，和 references 内容一致",
    )
    provider_task_id: str | None = Field(None, description="第三方服务商任务ID，旧表使用 seedance_task_id 兼容填充")
    seedance_task_id: str | None = Field(None, description="旧服务命名的第三方任务ID字段")
    remote_result_url: str | None = Field(
        None,
        description="第三方远程结果地址。旧 generation_records 未保存该字段，固定为 null",
    )
    image_url: str | None = Field(None, description="最终图片地址。图片记录完成后通常有值")
    video_url: str | None = Field(None, description="最终视频地址。视频记录完成后通常有值")
    video_cover_url: str | None = Field(None, description="视频封面图片地址。视频记录完成且封面截帧成功后通常有值")
    engine_id: str | None = Field(
        None,
        description="兼容新历史结构的引擎ID字段。旧 generation_records 未保存该字段，固定为 null",
    )
    engine_snapshot: dict | None = Field(
        None,
        description="兼容新历史结构的引擎快照字段。旧 generation_records 未保存该字段，固定为 null",
    )
    credits_cost: float = Field(0.0, description="本次记录总消耗积分")
    text_credits_cost: float = Field(0.0, description="文本优化或文本处理消耗积分")
    text_tokens_used: int = Field(0, description="文本 token 使用量")
    image_tokens_used: int = Field(0, description="图片 token 使用量")
    video_tokens_used: int = Field(0, description="视频 token 使用量")
    retry_count: int = Field(
        0,
        description="兼容新历史结构的重试次数字段。旧 generation_records 未保存该字段，固定为 0",
    )
    poll_count: int = Field(
        0,
        description="兼容新历史结构的轮询次数字段。旧 generation_records 未保存该字段，固定为 0",
    )
    error_message: str | None = Field(None, description="错误信息。成功记录一般为 null")
    created_at: NaiveDatetimeOptional = Field(None, description="记录创建时间")
    generated_at: NaiveDatetimeOptional = Field(None, description="生成完成时间")


GenerationAIHistoryItemOut = Annotated[
    GenerationAITaskOut | GenerationAIRecordHistoryItemOut,
    Field(discriminator="source_type"),
]


class GenerationAIHistoryDayGroupOut(BaseModel):
    """AI生成历史按天分组响应项。"""

    model_config = ConfigDict(
        json_schema_extra={
            "example": {
                "generated_date": "2026-05-27",
                "total": 18,
                "items": [],
            }
        }
    )

    generated_date: str = Field(..., description="生成日期，格式：YYYY-MM-DD")
    total: int = Field(..., description="当前生成日期下的生成成功记录总数")
    items: list[GenerationAIHistoryItemOut] = Field(
        default_factory=list,
        description=(
            "当前生成日期下倒序前10条生成记录详情。"
            "默认 history_source=chat_task 时 item 为 GenerationAITaskOut；"
            "history_source=generation_record 时 item 为 GenerationAIRecordHistoryItemOut"
        ),
    )


class GenerationAIHistoryGroupedOut(BaseModel):
    """AI生成历史日期分组列表响应体。"""

    model_config = ConfigDict(
        json_schema_extra={
            "example": {
                "total_days": 2,
                "page": 1,
                "page_size": 10,
                "groups": [
                    {
                        "generated_date": "2026-05-27",
                        "total": 18,
                        "items": [],
                    },
                    {
                        "generated_date": "2026-05-26",
                        "total": 6,
                        "items": [],
                    },
                ],
            }
        }
    )

    total_days: int = Field(..., description="当前生成类型下，用户一共有多少个生成日期分组")
    page: int = Field(..., description="当前日期分组分页页码")
    page_size: int = Field(..., description="当前每页返回的日期分组数量，最大10")
    groups: list[GenerationAIHistoryDayGroupOut] = Field(
        default_factory=list,
        description="按生成日期倒序排列的历史记录分组列表",
    )


class GenerationAIHistoryDayItemsOut(BaseModel):
    """指定日期下AI生成历史分页响应体。"""

    model_config = ConfigDict(
        json_schema_extra={
            "example": {
                "generated_date": "2026-05-27",
                "total": 18,
                "page": 2,
                "page_size": 10,
                "items": [],
            }
        }
    )

    generated_date: str = Field(..., description="当前查询的生成日期，格式：YYYY-MM-DD")
    total: int = Field(..., description="当前日期下的生成成功记录总数")
    page: int = Field(..., description="当前日期下的记录分页页码")
    page_size: int = Field(..., description="当前日期下每页返回的生成记录数量")
    items: list[GenerationAIHistoryItemOut] = Field(
        default_factory=list,
        description=(
            "当前日期下的生成记录详情列表，按 generated_at 倒序排列。"
            "默认 history_source=chat_task 时 item 为 GenerationAITaskOut；"
            "history_source=generation_record 时 item 为 GenerationAIRecordHistoryItemOut"
        ),
    )