from datetime import datetime
from typing import List, Optional, TYPE_CHECKING
from sqlalchemy import String, Integer, ForeignKey, DateTime, BigInteger, Enum as SQLEnum, func, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column, relationship
import enum

from ..database import Base

if TYPE_CHECKING:
    from ..db_models import Opening


class ThemeType(str, enum.Enum):
    """Type of anime theme (opening or ending)."""
    OP = "OP"
    ED = "ED"


class DownloadStatus(str, enum.Enum):
    """Status of a download task."""
    QUEUED = "queued"
    DOWNLOADING = "downloading"
    CONVERTING = "converting"
    UPLOADING = "uploading"
    DONE = "done"
    FAILED = "failed"


class Anime(Base):
    """Anime entity from AnimeThemes."""
    __tablename__ = "anime"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    animethemes_slug: Mapped[str] = mapped_column(String(255), unique=True, index=True, nullable=False)

    title_russian: Mapped[Optional[str]] = mapped_column(String(500), nullable=True)
    title_english: Mapped[Optional[str]] = mapped_column(String(500), nullable=True)
    title_japanese: Mapped[Optional[str]] = mapped_column(String(500), nullable=True)

    year: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    poster_url: Mapped[Optional[str]] = mapped_column(String(1024), nullable=True)

    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        server_default=func.now()
    )

    # Relationships
    themes: Mapped[List["AnimeTheme"]] = relationship(
        "AnimeTheme",
        back_populates="anime",
        cascade="all, delete-orphan"
    )

    def __repr__(self):
        return f"<Anime {self.animethemes_slug}: {self.title_english}>"


class AnimeTheme(Base):
    """Anime opening/ending theme."""
    __tablename__ = "anime_themes"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    anime_id: Mapped[int] = mapped_column(
        Integer,
        ForeignKey("anime.id", ondelete="CASCADE"),
        nullable=False
    )

    theme_type: Mapped[ThemeType] = mapped_column(
        SQLEnum(ThemeType, native_enum=False),
        nullable=False
    )
    sequence: Mapped[int] = mapped_column(Integer, nullable=False, default=1)  # 1, 2, 3...
    song_title: Mapped[Optional[str]] = mapped_column(String(500), nullable=True)
    artist: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)

    # AnimeThemes video URL (WebM source)
    animethemes_video_url: Mapped[Optional[str]] = mapped_column(String(1024), nullable=True)

    # Downloaded file info
    audio_s3_key: Mapped[Optional[str]] = mapped_column(String(512), nullable=True)
    file_size_bytes: Mapped[Optional[int]] = mapped_column(BigInteger, nullable=True)

    # Link to existing Opening entity (after download)
    opening_id: Mapped[Optional[int]] = mapped_column(
        Integer,
        ForeignKey("openings.id", ondelete="SET NULL"),
        nullable=True
    )

    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        server_default=func.now()
    )

    # Unique constraint: one anime can have only one OP1, OP2, ED1, etc.
    __table_args__ = (
        UniqueConstraint('anime_id', 'theme_type', 'sequence', name='uq_anime_theme_sequence'),
    )

    # Relationships
    anime: Mapped["Anime"] = relationship("Anime", back_populates="themes")
    opening: Mapped[Optional["Opening"]] = relationship("Opening")

    @property
    def full_name(self) -> str:
        """Return full theme name like 'OP1' or 'ED2'."""
        return f"{self.theme_type.value}{self.sequence}"

    @property
    def is_downloaded(self) -> bool:
        """Check if theme has been downloaded."""
        return self.audio_s3_key is not None

    def __repr__(self):
        return f"<AnimeTheme {self.full_name}: {self.song_title}>"


class DownloadTask(Base):
    """Download queue task."""
    __tablename__ = "download_tasks"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    theme_id: Mapped[int] = mapped_column(
        Integer,
        ForeignKey("anime_themes.id", ondelete="CASCADE"),
        nullable=False,
        unique=True  # One task per theme
    )

    status: Mapped[DownloadStatus] = mapped_column(
        SQLEnum(DownloadStatus, native_enum=False),
        nullable=False,
        default=DownloadStatus.QUEUED
    )

    # Progress tracking
    progress_percent: Mapped[int] = mapped_column(Integer, default=0)
    error_message: Mapped[Optional[str]] = mapped_column(String(1024), nullable=True)

    # Estimated size (6 MB default if unknown)
    estimated_size_bytes: Mapped[int] = mapped_column(BigInteger, default=6_291_456)  # 6 MB

    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        server_default=func.now()
    )
    started_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
    completed_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)

    # Relationships
    theme: Mapped["AnimeTheme"] = relationship("AnimeTheme")

    def __repr__(self):
        return f"<DownloadTask {self.id}: {self.status.value}>"
