from __future__ import annotations

import sys
from dataclasses import dataclass, field
from datetime import datetime, timezone

if sys.version_info >= (3, 11):
    from enum import StrEnum
else:
    from enum import Enum

    class StrEnum(str, Enum):
        pass


from typing import Any
from uuid import uuid4


class AssetLibraryKind(StrEnum):
    VIDEO = "video"
    VOICE = "voice"
    IMAGE = "image"


class IngestJobStatus(StrEnum):
    PENDING = "pending"
    PROCESSING = "processing"
    COMPLETED = "completed"
    FAILED = "failed"


@dataclass(slots=True)
class User:
    id: str
    email: str
    display_name: str
    username: str = ""
    # 认证相关字段
    password_hash: str = ""
    email_verified: bool = False
    email_verification_token: str | None = None
    password_reset_token: str | None = None
    password_reset_expires_at: datetime | None = None
    last_login_at: datetime | None = None
    last_login_ip: str | None = None
    # 订阅相关字段 (移到 User 级别)
    subscription_plan: str = "free"  # free, pro, enterprise
    subscription_status: str = "active"  # active, cancelled, expired
    subscription_expires_at: datetime | None = None
    # 配额限制 (移到 User 级别)
    max_projects: int = 3  # free: 3, pro: unlimited, enterprise: unlimited
    max_storage_gb: int = 10  # free: 10, pro: 100, enterprise: 1000
    used_storage_gb: float = 0.0
    # 管理员标识
    is_admin: bool = False

    # 微信绑定
    wechat_openid: str | None = None
    wechat_unionid: str | None = None

    created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))


@dataclass(slots=True)
class Project:
    id: str
    owner_user_id: str
    name: str
    description: str = ""
    shared_users: list[str] = field(default_factory=list)  # 被共享的用户 ID 列表
    created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))

    @classmethod
    def create(cls, owner_user_id: str, name: str, description: str = "") -> "Project":
        clean_name = name.strip()
        if not clean_name:
            raise ValueError("项目名称不能为空")
        return cls(
            id=uuid4().hex,
            owner_user_id=owner_user_id,
            name=clean_name,
            description=description.strip(),
            shared_users=[],
        )

    def is_owner(self, user_id: str) -> bool:
        """检查用户是否为项目所有者"""
        return self.owner_user_id == user_id

    def is_shared_with(self, user_id: str) -> bool:
        """检查项目是否共享给指定用户"""
        return user_id in self.shared_users

    def can_access(self, user_id: str) -> bool:
        """检查用户是否有权限访问项目"""
        return self.is_owner(user_id) or self.is_shared_with(user_id)


@dataclass(slots=True)
class AssetLibrary:
    id: str
    project_id: str
    name: str
    kind: AssetLibraryKind
    asset_count: int = 0
    total_size: int = 0
    created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
    updated_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))

    @classmethod
    def create(
        cls,
        project_id: str,
        name: str,
        kind: AssetLibraryKind,
    ) -> "AssetLibrary":
        clean_name = name.strip()
        if not clean_name:
            raise ValueError("素材库名称不能为空")
        return cls(
            id=uuid4().hex,
            project_id=project_id,
            name=clean_name,
            kind=kind,
            asset_count=0,
            total_size=0,
        )


class AssetStatus(StrEnum):
    UPLOADING = "uploading"
    READY = "ready"
    PROCESSING = "processing"
    ERROR = "error"


class ClassificationStatus(StrEnum):
    PENDING = "pending"
    PROCESSING = "processing"
    COMPLETED = "completed"
    FAILED = "failed"


@dataclass(slots=True)
class Asset:
    id: str
    project_id: str
    library_id: str
    name: str
    storage_key: str
    mime_type: str
    file_size: int = 0
    thumbnail_url: str | None = None
    duration: float | None = None
    width: int | None = None
    height: int | None = None
    fps: float | None = None
    codec: str | None = None
    status: AssetStatus = AssetStatus.UPLOADING
    classification_status: ClassificationStatus = ClassificationStatus.PENDING
    quality_score: float | None = None
    uploaded_by_user_id: str = ""
    file_hash: str = ""
    metadata: dict[str, Any] = field(default_factory=dict)
    tag_ids: list[str] = field(default_factory=list)
    created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
    updated_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))

    @classmethod
    def create(
        cls,
        project_id: str,
        library_id: str,
        name: str,
        storage_key: str,
        mime_type: str,
        metadata: dict[str, Any] | None = None,
        *,
        file_size: int = 0,
        thumbnail_url: str | None = None,
        duration: float | None = None,
        width: int | None = None,
        height: int | None = None,
        fps: float | None = None,
        codec: str | None = None,
        status: AssetStatus = AssetStatus.UPLOADING,
        classification_status: ClassificationStatus = ClassificationStatus.PENDING,
        quality_score: float | None = None,
        uploaded_by_user_id: str = "",
        file_hash: str = "",
    ) -> "Asset":
        clean_name = name.strip()
        if not clean_name:
            raise ValueError("素材名称不能为空")
        if not storage_key.strip():
            raise ValueError("storage_key 不能为空")
        if not mime_type.strip():
            raise ValueError("mime_type 不能为空")
        return cls(
            id=uuid4().hex,
            project_id=project_id,
            library_id=library_id,
            name=clean_name,
            storage_key=storage_key.strip(),
            mime_type=mime_type.strip(),
            file_size=file_size,
            thumbnail_url=thumbnail_url,
            duration=duration,
            width=width,
            height=height,
            fps=fps,
            codec=codec,
            status=status,
            classification_status=classification_status,
            quality_score=quality_score,
            uploaded_by_user_id=uploaded_by_user_id.strip(),
            file_hash=file_hash.strip(),
            metadata=metadata or {},
            tag_ids=[],
        )

    def add_tag(self, tag_id: str) -> None:
        """添加标签 ID。空 ID 会被忽略，自动去重。"""
        clean_id = tag_id.strip()
        if not clean_id:
            raise ValueError("标签 ID 不能为空")
        if clean_id not in self.tag_ids:
            self.tag_ids.append(clean_id)
            self.updated_at = datetime.now(timezone.utc)

    def remove_tag(self, tag_id: str) -> None:
        """删除标签 ID。如果标签不存在，不报错（幂等性）。"""
        clean_id = tag_id.strip()
        if clean_id in self.tag_ids:
            self.tag_ids.remove(clean_id)
            self.updated_at = datetime.now(timezone.utc)


@dataclass(slots=True)
class IngestJob:
    id: str
    project_id: str
    library_id: str
    storage_key: str
    status: IngestJobStatus = IngestJobStatus.PENDING
    error_message: str = ""
    result_asset_id: str = ""
    file_hash: str = ""
    created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
    updated_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))

    @classmethod
    def create(
        cls,
        project_id: str,
        library_id: str,
        storage_key: str,
        file_hash: str = "",
    ) -> "IngestJob":
        if not project_id.strip():
            raise ValueError("project_id 不能为空")
        if not library_id.strip():
            raise ValueError("library_id 不能为空")
        if not storage_key.strip():
            raise ValueError("storage_key 不能为空")
        return cls(
            id=uuid4().hex,
            project_id=project_id.strip(),
            library_id=library_id.strip(),
            storage_key=storage_key.strip(),
            file_hash=file_hash.strip(),
        )
