"""
app/models/task.py — generation_tasks / text_candidates / image_candidates / delivery_packages
Alembic 003 业务主体（2/3）
任务主键：自增 BIGINT + mongo_trace_id VARCHAR(24)
eval_score 留 NULL，不接 banana 假评分（基石）
"""

from datetime import datetime
from typing import Optional

from sqlalchemy import (
    BigInteger, Boolean, DateTime, Enum, Float, ForeignKey,
    Index, Integer, String, Text, func,
)
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.constants.enums import (
    BannedWordStatus, CandidateSource, ImageRole,
    PackageStatus, ReviewStatus, TaskStatus,
)
from app.core.database import Base


class GenerationTask(Base):
    """生产任务，审核字段平铺（不建独立审核表）。"""
    __tablename__ = "generation_tasks"

    id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
    workspace_id: Mapped[int] = mapped_column(
        BigInteger, ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False
    )
    product_id: Mapped[int] = mapped_column(
        BigInteger, ForeignKey("products.id"), nullable=False
    )
    operator_id: Mapped[int] = mapped_column(
        BigInteger, ForeignKey("users.id"), nullable=False
    )
    theme: Mapped[str | None] = mapped_column(String(256))
    text_count: Mapped[int] = mapped_column(Integer, default=5, nullable=False)
    image_count: Mapped[int] = mapped_column(Integer, default=3, nullable=False)
    track: Mapped[str] = mapped_column(String(16), default="ai", nullable=False)
    # 本次产品是否入镜：True=必须用产品参考图(无图禁生成,不降级纯文生图)；False=允许纯文生图
    need_product_image: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
    status: Mapped[str] = mapped_column(
        Enum(TaskStatus, values_callable=lambda x: [e.value for e in x]),
        default=TaskStatus.PENDING, nullable=False,
    )
    mongo_trace_id: Mapped[str | None] = mapped_column(String(24))  # MongoDB trace
    # ── 审核字段（平铺）──────────────────────────────
    review_status: Mapped[str | None] = mapped_column(
        Enum(ReviewStatus, values_callable=lambda x: [e.value for e in x])
    )
    reviewer_id: Mapped[int | None] = mapped_column(BigInteger, ForeignKey("users.id"))
    reviewed_at: Mapped[datetime | None] = mapped_column(DateTime)
    reject_reason: Mapped[str | None] = mapped_column(Text)
    approved_at: Mapped[datetime | None] = mapped_column(DateTime)
    archived_at: Mapped[datetime | None] = mapped_column(DateTime)
    # 011: 第2环S12+第11环裂变
    benchmark_ids: Mapped[str | None] = mapped_column(Text, comment="关联标杆笔记ID列表（JSON list），第2环引用")
    source_fission_id: Mapped[int | None] = mapped_column(Integer, comment="裂变来源fission_task ID；NULL=普通任务")
    created_at: Mapped[datetime] = mapped_column(
        DateTime, server_default=func.now(), nullable=False
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime, server_default=func.now(), onupdate=func.now(), nullable=False
    )

    __table_args__ = (
        Index("idx_generation_tasks_workspace_status", "workspace_id", "status"),
    )


class TextCandidate(Base):
    """文案候选（source=ai/import 区分双轨）。eval_score 留 NULL。"""
    __tablename__ = "text_candidates"

    id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
    workspace_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
    task_id: Mapped[int] = mapped_column(
        BigInteger, ForeignKey("generation_tasks.id", ondelete="CASCADE"), nullable=False
    )
    source: Mapped[str] = mapped_column(
        Enum(CandidateSource, values_callable=lambda x: [e.value for e in x]),
        default=CandidateSource.AI, nullable=False,
    )
    angle_label: Mapped[str | None] = mapped_column(String(64))
    content: Mapped[str | None] = mapped_column(Text)
    score_json: Mapped[str | None] = mapped_column(Text)    # 五维分 JSON
    banned_word_status: Mapped[str] = mapped_column(
        Enum(BannedWordStatus, values_callable=lambda x: [e.value for e in x]),
        default=BannedWordStatus.PASS, nullable=False,
    )
    eval_score: Mapped[float | None] = mapped_column(Float)  # 一期留 NULL
    is_selected: Mapped[bool] = mapped_column(default=False, nullable=False)
    created_at: Mapped[datetime] = mapped_column(
        DateTime, server_default=func.now(), nullable=False
    )

    __table_args__ = (
        Index("idx_text_candidates_task_id", "task_id"),
    )


class ImageCandidate(Base):
    """图片候选。eval_score 留 NULL。"""
    __tablename__ = "image_candidates"

    id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
    workspace_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
    task_id: Mapped[int] = mapped_column(
        BigInteger, ForeignKey("generation_tasks.id", ondelete="CASCADE"), nullable=False
    )
    # role 用 varchar 不用 enum：storyboard 角色名仍在演进，约束放应用层 ImageRole
    role: Mapped[str] = mapped_column(
        String(32), default=ImageRole.HOOK.value, nullable=False,
    )
    url: Mapped[str | None] = mapped_column(String(512))
    strategy: Mapped[str | None] = mapped_column(String(4))    # A/B/C（二期）
    seq: Mapped[int] = mapped_column(Integer, default=1)        # 分镜序号
    is_selected: Mapped[bool] = mapped_column(default=False, nullable=False)
    eval_score: Mapped[float | None] = mapped_column(Float)     # 一期留 NULL
    created_at: Mapped[datetime] = mapped_column(
        DateTime, server_default=func.now(), nullable=False
    )

    __table_args__ = (
        Index("idx_image_candidates_task_id", "task_id"),
    )


class DeliveryPackage(Base):
    """达人素材交付包。"""
    __tablename__ = "delivery_packages"

    id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
    workspace_id: Mapped[int] = mapped_column(
        BigInteger, ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False
    )
    task_id: Mapped[int] = mapped_column(
        BigInteger, ForeignKey("generation_tasks.id"), nullable=False
    )
    status: Mapped[str] = mapped_column(
        Enum(PackageStatus, values_callable=lambda x: [e.value for e in x]),
        default=PackageStatus.PENDING, nullable=False,
    )
    package_path: Mapped[str | None] = mapped_column(String(512))
    download_url: Mapped[str | None] = mapped_column(String(512))
    expires_at: Mapped[datetime | None] = mapped_column(DateTime)
    created_at: Mapped[datetime] = mapped_column(
        DateTime, server_default=func.now(), nullable=False
    )
