from datetime import datetime, timezone

from sqlalchemy import JSON, Boolean, Column, DateTime, Float, Integer, String, Text, UniqueConstraint, create_engine
from sqlalchemy.orm import declarative_base

Base = declarative_base()


class UserModel(Base):
    __tablename__ = "users"

    id = Column(String(36), primary_key=True)
    email = Column(String(255), nullable=False, unique=True, index=True)
    username = Column(String(100), nullable=True, unique=True, index=True)
    display_name = Column(String(255), nullable=False)
    password_hash = Column(String(255), nullable=False)
    email_verified = Column(Boolean, nullable=False, default=False)
    email_verification_token = Column(String(255), nullable=True)
    password_reset_token = Column(String(255), nullable=True)
    password_reset_expires_at = Column(DateTime, nullable=True)
    last_login_at = Column(DateTime, nullable=True)
    last_login_ip = Column(String(50), nullable=True)
    # 订阅相关字段 (移到 User 级别)
    subscription_plan = Column(String(20), nullable=False, default="free")
    subscription_status = Column(String(20), nullable=False, default="active")
    subscription_expires_at = Column(DateTime, nullable=True)
    # 配额限制 (移到 User 级别)
    max_projects = Column(Integer, nullable=False, default=3)
    max_storage_gb = Column(Integer, nullable=False, default=10)
    used_storage_gb = Column(Integer, nullable=False, default=0)
    # 管理员标识
    is_admin = Column(Boolean, nullable=False, default=False)
    # 微信登录（小程序端）
    wechat_openid = Column(String(128), nullable=True, unique=True, index=True)
    wechat_unionid = Column(String(128), nullable=True, unique=True, index=True)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class ProjectModel(Base):
    __tablename__ = "projects"

    id = Column(String(32), primary_key=True)
    owner_user_id = Column(String(32), nullable=False, index=True)
    name = Column(String(100), nullable=False)
    description = Column(Text, nullable=False, default="")
    shared_users = Column(JSON, nullable=False, default=list)  # 被共享的用户 ID 列表
    extra_meta = Column("metadata", JSON, nullable=False, default=dict)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class AssetLibraryModel(Base):
    __tablename__ = "asset_libraries"

    id = Column(String(36), primary_key=True)
    project_id = Column(String(36), nullable=True, index=True)
    name = Column(String(255), nullable=False)
    kind = Column(String(20), nullable=False, index=True)
    asset_count = Column(Float, nullable=False, default=0)
    total_size = Column(Float, nullable=False, default=0)
    extra_meta = Column("metadata", JSON, nullable=False, default=dict)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class AssetModel(Base):
    __tablename__ = "assets"

    id = Column(String(36), primary_key=True)
    project_id = Column(String(36), nullable=False, index=True)
    asset_library_id = Column(String(36), nullable=False, index=True)
    name = Column(String(500), nullable=False)
    file_type = Column(String(20), nullable=False, index=True)
    # file_size: 文件大小（字节），使用 Integer 类型以确保精确性
    file_size = Column(Integer, nullable=False)
    # file_url: 完整可访问的 URL，用于客户端直接访问文件
    file_url = Column(String(1000), nullable=False)
    thumbnail_url = Column(String(1000), nullable=True)
    duration = Column(Float, nullable=True)
    width = Column(Float, nullable=True)
    height = Column(Float, nullable=True)
    fps = Column(Float, nullable=True)
    codec = Column(String(50), nullable=True)
    status = Column(String(20), nullable=False, default="uploading", index=True)
    classification_status = Column(String(20), nullable=False, default="pending", index=True)
    classification_result = Column(Text, nullable=True)
    quality_score = Column(Float, nullable=True)
    uploaded_by_user_id = Column(String(36), nullable=False)
    file_hash = Column(String(64), nullable=True, index=True)
    extra_meta = Column("metadata", JSON, nullable=False, default=dict)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc), index=True)
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class TagModel(Base):
    """标签 ORM 模型。"""

    __tablename__ = "tags"

    id = Column(String(36), primary_key=True)
    user_id = Column(String(36), nullable=False, index=True)
    name = Column(String(100), nullable=False)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))

    __table_args__ = (UniqueConstraint("user_id", "name", name="uq_tags_user_name"),)


class AssetTagModel(Base):
    """素材-标签关联表 ORM 模型。"""

    __tablename__ = "asset_tags"

    asset_id = Column(String(36), primary_key=True)
    tag_id = Column(String(36), primary_key=True)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class EditTemplateModel(Base):
    """Phase 8 剪辑模板 ORM 模型

    全局模板库中的模板，定义剪辑风格、配置参数和预览信息。
    """

    __tablename__ = "edit_templates"

    id = Column(String(32), primary_key=True)
    name = Column(String(120), nullable=False)
    description = Column(Text, nullable=False, default="")
    template_type = Column(String(50), nullable=False, default="default", index=True)
    config = Column(JSON, nullable=False, default=dict)
    preview_url = Column(String(1000), nullable=False, default="")
    sort_weight = Column(Integer, nullable=False, default=0, index=True)
    status = Column(String(20), nullable=False, default="active", index=True)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class EditPlanModel(Base):
    """Phase 8 剪辑计划 ORM 模型

    基于某个 EditTemplate 创建的剪辑计划，包含具体的配置和状态追踪。
    """

    __tablename__ = "edit_plans"

    id = Column(String(32), primary_key=True)
    template_id = Column(String(32), nullable=False, index=True)
    name = Column(String(200), nullable=False)
    status = Column(String(20), nullable=False, default="draft", index=True)
    total_duration = Column(Float, nullable=False, default=0.0)
    config = Column(JSON, nullable=False, default=dict)
    source_edit_plan_id = Column(String(32), nullable=True, index=True)
    project_id = Column(String(32), nullable=False, default="", index=True)
    created_by_user_id = Column(String(32), nullable=False, default="", index=True)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class TemplateClipConfigModel(Base):
    """Phase 8 模板片段配置 ORM 模型

    定义模板中每个片段的规则：类型、时长范围、文案模板、素材要求、转场效果。
    """

    __tablename__ = "template_clip_configs"

    id = Column(String(32), primary_key=True)
    template_id = Column(String(32), nullable=False, index=True)
    clip_type = Column(String(20), nullable=False, index=True)
    order = Column(Integer, nullable=False)
    min_duration = Column(Float, nullable=False, default=0.0)
    max_duration = Column(Float, nullable=False, default=0.0)
    text_template = Column(Text, nullable=False, default="")
    material_requirements = Column(JSON, nullable=False, default=dict)
    transition_effect = Column(String(20), nullable=False, default="cut")
    config = Column(JSON, nullable=False, default=dict)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class EditPlanClipModel(Base):
    """Phase 8 剪辑计划片段 ORM 模型

    剪辑计划中的具体片段实例，关联 EditPlan 和可选的 TemplateClipConfig。
    """

    __tablename__ = "edit_plan_clips"

    id = Column(String(32), primary_key=True)
    plan_id = Column(String(32), nullable=False, index=True)
    clip_type = Column(String(20), nullable=False, index=True)
    order = Column(Integer, nullable=False)
    template_clip_config_id = Column(String(32), nullable=False, default="", index=True)
    asset_id = Column(String(32), nullable=False, default="", index=True)
    text_content = Column(Text, nullable=False, default="")
    start_time = Column(Float, nullable=False, default=0.0)
    duration = Column(Float, nullable=False, default=0.0)
    transition_effect = Column(String(20), nullable=False, default="cut")
    status = Column(String(20), nullable=False, default="pending", index=True)
    config = Column(JSON, nullable=False, default=dict)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class IngestJobModel(Base):
    __tablename__ = "ingest_jobs"

    id = Column(String(32), primary_key=True)
    project_id = Column(String(32), nullable=False, index=True)
    library_id = Column(String(32), nullable=False, index=True)
    storage_key = Column(String(255), nullable=False)
    status = Column(String(20), nullable=False, default="pending")
    error_message = Column(Text, nullable=False, default="")
    result_asset_id = Column(String(32), nullable=False, default="")
    file_hash = Column(String(64), nullable=True, index=True)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class ClassificationJobModel(Base):
    __tablename__ = "classification_jobs"

    id = Column(String(32), primary_key=True)
    project_id = Column(String(32), nullable=False, index=True)
    asset_id = Column(String(32), nullable=False, index=True)
    status = Column(String(20), nullable=False, default="pending")
    classification = Column(String(50), nullable=False, default="")
    confidence = Column(Float, nullable=False, default=0.0)
    error_message = Column(Text, nullable=False, default="")
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class GenerationTaskModel(Base):
    __tablename__ = "generation_tasks"

    id = Column(String(32), primary_key=True)
    project_id = Column(String(32), nullable=False, default="", index=True)
    strategy_id = Column(String(32), nullable=False, default="")
    asset_library_id = Column(String(32), nullable=False, default="", index=True)
    voice_library_id = Column(String(32), nullable=False, default="")
    template_id = Column(String(36), nullable=False, default="", index=True)
    asset_ids = Column(JSON, nullable=False, default=list)
    title_ids = Column(JSON, nullable=False, default=list)
    voice_ids = Column(JSON, nullable=False, default=list)
    editing_mode = Column(
        String(20), nullable=False, default="one_take", index=True
    )  # 剪辑模式: one_take, pip, voice_over, voice_pip
    status = Column(String(20), nullable=False, default="pending", index=True)
    progress = Column(Float, nullable=False, default=0.0)
    result_count = Column(Float, nullable=False, default=0)
    error_message = Column(Text, nullable=False, default="")
    started_at = Column(DateTime, nullable=True)
    completed_at = Column(DateTime, nullable=True)
    created_by_user_id = Column(String(32), nullable=False, default="", index=True)
    source_edit_plan_id = Column(String(32), nullable=True, index=True)
    asset_select_mode = Column(String(20), nullable=False, default="")
    batch_id = Column(String(32), nullable=False, default="", index=True)
    is_preview = Column(Boolean, nullable=False, default=True)
    source_task_id = Column(String(32), nullable=False, default="", index=True)
    output_width = Column(Integer, nullable=False, default=1280)
    output_height = Column(Integer, nullable=False, default=720)
    cover_url = Column(String(1000), nullable=False, default="")
    custom_title = Column(String(500), nullable=False, default="")
    extra_meta = Column("metadata", JSON, nullable=False, default=dict)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class GeneratedVideoModel(Base):
    __tablename__ = "generated_videos"

    id = Column(String(32), primary_key=True)
    project_id = Column(String(32), nullable=False, index=True)
    generation_task_id = Column(String(32), nullable=False, index=True)
    name = Column(String(255), nullable=False)
    # file_url: 完整可访问的 URL，用于客户端直接访问视频
    file_url = Column(String(1000), nullable=False)
    # file_size: 文件大小（字节），使用 Integer 类型以确保精确性
    file_size = Column(Integer, nullable=False)
    duration = Column(Float, nullable=False)
    thumbnail_url = Column(String(1000), nullable=True)
    width = Column(Float, nullable=False)
    height = Column(Float, nullable=False)
    fps = Column(Float, nullable=False)
    status = Column(String(20), nullable=False, default="completed", index=True)
    review_status = Column(String(20), nullable=False, default="pending_review", index=True)
    generation_params = Column(Text, nullable=False, default="{}")
    generated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=True)
    video_fingerprint = Column(Text, nullable=True)
    is_duplicate = Column(Boolean, nullable=False, default=False)
    duplicate_of = Column(String(32), nullable=True)


class TitleLibraryModel(Base):
    __tablename__ = "title_libraries"

    id = Column(String(36), primary_key=True)
    user_id = Column(String(36), nullable=False, index=True)
    name = Column(String(255), nullable=False)
    description = Column(Text, nullable=False, default="")
    category = Column(String(50), nullable=False, default="default", index=True)
    text = Column(String(500), nullable=False)
    tags = Column(JSON, nullable=False, default=list)
    usage_count = Column(Integer, nullable=False, default=0)
    is_active = Column(Boolean, nullable=False, default=True, index=True)
    extra_meta = Column("metadata", JSON, nullable=False, default=dict)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class VoiceCloneProfileModel(Base):
    """音色克隆档案 ORM 模型。"""

    __tablename__ = "voice_clone_profiles"

    id = Column(String(36), primary_key=True)
    user_id = Column(String(36), nullable=False, index=True)
    name = Column(String(100), nullable=False)
    description = Column(Text, nullable=False, default="")
    source_audio_url = Column(Text, nullable=False, default="")
    voice_id = Column(String(100), nullable=False, default="")
    voice_model = Column(String(100), nullable=False, default="")
    language = Column(String(20), nullable=False, default="zh-CN")
    gender = Column(String(20), nullable=False, default="unknown")
    status = Column(String(20), nullable=False, default="pending", index=True)
    error_message = Column(Text, nullable=False, default="")
    retry_count = Column(Integer, nullable=False, default=0)
    max_retries = Column(Integer, nullable=False, default=3)
    metadata_ = Column("metadata", JSON, nullable=False, default=dict)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class VoiceLibraryModel(Base):
    __tablename__ = "voice_libraries"

    id = Column(String(36), primary_key=True)
    user_id = Column(String(36), nullable=False, index=True)
    project_id = Column(String(36), nullable=True, index=True)
    name = Column(String(255), nullable=False)
    text = Column(Text, nullable=False, default="")
    voice_provider = Column(String(50), nullable=False, default="")
    voice_id = Column(String(100), nullable=False, default="")
    voice_name = Column(String(100), nullable=False, default="")
    audio_url = Column(String(1000), nullable=False, default="")
    duration = Column(Float, nullable=False, default=0)
    file_size = Column(Integer, nullable=False, default=0)
    status = Column(String(20), nullable=False, default="completed", index=True)
    tags = Column(JSON, nullable=False, default=list)
    extra_meta = Column("metadata", JSON, nullable=False, default=dict)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class DuplicationRecordModel(Base):
    __tablename__ = "duplication_records"

    id = Column(String(36), primary_key=True)
    user_id = Column(String(36), nullable=False, index=True)
    filename = Column(String(500), nullable=False)
    file_size = Column(Integer, nullable=False)
    storage_key = Column(String(500), nullable=False)
    duration_seconds = Column(Float, nullable=False, default=0)
    status = Column(String(20), nullable=False, default="pending", index=True)
    duplicate_rate = Column(Float, nullable=True)
    duplicate_count = Column(Integer, nullable=False, default=0)
    video_fingerprint = Column(Text, nullable=True)
    error_message = Column(Text, nullable=False, default="")
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class DuplicationSegmentModel(Base):
    __tablename__ = "duplication_segments"

    id = Column(String(36), primary_key=True)
    record_id = Column(String(36), nullable=False, index=True)
    source_start = Column(Float, nullable=False)
    source_end = Column(Float, nullable=False)
    matched_video_id = Column(String(36), nullable=False)
    matched_video_name = Column(String(500), nullable=False, default="")
    matched_start = Column(Float, nullable=False)
    matched_end = Column(Float, nullable=False)
    similarity = Column(Float, nullable=False)


class RecipeModel(Base):
    __tablename__ = "recipes"

    id = Column(String(36), primary_key=True)
    user_id = Column(String(36), nullable=False, index=True)
    name = Column(String(200), nullable=False)
    description = Column(Text, nullable=False, default="")
    template_id = Column(String(36), nullable=False, default="")
    generation_params = Column(JSON, nullable=False, default=dict)
    is_active = Column(Boolean, nullable=False, default=True)
    extra_meta = Column("metadata", JSON, nullable=False, default=dict)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class RecipeItemModel(Base):
    __tablename__ = "recipe_items"

    id = Column(String(36), primary_key=True)
    recipe_id = Column(String(36), nullable=False, index=True)
    item_type = Column(String(20), nullable=False)
    item_id = Column(String(36), nullable=False)
    position = Column(Integer, nullable=False, default=0)
    extra_meta = Column("metadata", JSON, nullable=False, default=dict)


class TemplateModel(Base):
    __tablename__ = "templates"

    id = Column(String(36), primary_key=True)
    user_id = Column(String(36), nullable=False, index=True)
    name = Column(String(200), nullable=False)
    mode = Column(String(30), nullable=False, index=True)  # EditingMode 枚举值: pip / voice_pip / one_take / voice_over
    category = Column(String(100), nullable=False, default="")
    tags = Column(JSON, nullable=False, default=list)
    title_config = Column(JSON, nullable=False, default=dict)
    subtitle_config = Column(JSON, nullable=False, default=dict)
    bgm_config = Column(JSON, nullable=False, default=dict)
    estimated_duration = Column(Float, nullable=False, default=0.0)
    is_active = Column(Boolean, nullable=False, default=True)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class TemplateSegmentModel(Base):
    __tablename__ = "template_segments"

    id = Column(String(36), primary_key=True)
    template_id = Column(String(36), nullable=False, index=True)
    segment_order = Column(Integer, nullable=False)
    duration_min = Column(Float, nullable=False)
    duration_max = Column(Float, nullable=False)
    material_type = Column(String(20), nullable=True)  # 仅 voice_over 模式: 人物/场景
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class TemplateCategoryModel(Base):
    __tablename__ = "template_categories"

    id = Column(String(36), primary_key=True)
    user_id = Column(String(36), nullable=False, index=True)
    name = Column(String(100), nullable=False)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class JobModel(Base):
    """Phase 8 任务 2.10 — 统一异步任务 ORM 模型。"""

    __tablename__ = "jobs"

    id = Column(String(32), primary_key=True)
    project_id = Column(String(32), nullable=False, index=True)
    job_type = Column(String(30), nullable=False, index=True)
    status = Column(String(20), nullable=False, default="pending", index=True)
    progress = Column(Float, nullable=False, default=0.0)
    current_stage = Column(String(200), nullable=False, default="")
    payload = Column(JSON, nullable=False, default=dict)
    result = Column(JSON, nullable=False, default=dict)
    error_message = Column(Text, nullable=False, default="")
    retry_count = Column(Integer, nullable=False, default=0)
    max_retries = Column(Integer, nullable=False, default=3)
    celery_task_id = Column(String(100), nullable=False, default="")
    source_id = Column(String(32), nullable=False, default="", index=True)
    created_by_user_id = Column(String(32), nullable=False, default="", index=True)
    started_at = Column(DateTime, nullable=True)
    completed_at = Column(DateTime, nullable=True)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class TTSJobModel(Base):
    """TTS 合成任务 ORM 模型。"""

    __tablename__ = "tts_jobs"

    id = Column(String(36), primary_key=True)
    user_id = Column(String(36), nullable=False, index=True)
    input_text = Column(Text, nullable=False)
    voice_id = Column(String(100), nullable=False, default="")
    voice_model = Column(String(100), nullable=False, default="")
    project_id = Column(String(36), nullable=False, default="")
    voice_clone_profile_id = Column(String(36), nullable=False, default="")
    status = Column(String(20), nullable=False, default="pending", index=True)
    output_audio_url = Column(Text, nullable=False, default="")
    output_audio_key = Column(String(500), nullable=False, default="")
    duration = Column(Float, nullable=False, default=0.0)
    file_size = Column(Integer, nullable=False, default=0)
    sample_rate = Column(Integer, nullable=False, default=22050)
    format = Column(String(20), nullable=False, default="mp3")
    error_message = Column(Text, nullable=False, default="")
    retry_count = Column(Integer, nullable=False, default=0)
    max_retries = Column(Integer, nullable=False, default=3)
    metadata_ = Column("metadata", JSON, nullable=False, default=dict)
    started_at = Column(DateTime, nullable=True)
    completed_at = Column(DateTime, nullable=True)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))


class BillingRecordModel(Base):
    """账单记录"""

    __tablename__ = "billing_records"

    id = Column(String(36), primary_key=True)
    user_id = Column(String(36), nullable=False, index=True)
    plan_name = Column(String(50), nullable=False)
    amount = Column(Float, nullable=False)
    billing_cycle = Column(String(20), nullable=False)
    status = Column(String(20), nullable=False, default="pending")  # pending, paid, failed, refunded
    payment_method = Column(String(50), nullable=True)
    payment_id = Column(String(100), nullable=True)  # 第三方支付流水号
    invoice_url = Column(String(500), nullable=True)
    created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    paid_at = Column(DateTime, nullable=True)
