from datetime import datetime
from typing import Any, List, Optional

from sqlalchemy import String, JSON, Index, delete, or_
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column

from app.db.base import Base, execute_dml, get_id_column
from app.db.models._constraints import media_identity_constraint
from app.schemas.types import MediaSource


class MediaServerItem(Base):
    """
    媒体服务器媒体条目表
    """
    id = get_id_column()
    # 服务器类型
    server: Mapped[Optional[str]] = mapped_column(String)
    # 媒体库ID
    library: Mapped[Optional[str]] = mapped_column(String)
    # ID
    item_id: Mapped[Optional[str]] = mapped_column(String, index=True)
    # 类型
    item_type: Mapped[Optional[str]] = mapped_column(String)
    # 标题
    title: Mapped[Optional[str]] = mapped_column(String, index=True)
    # 原标题
    original_title: Mapped[Optional[str]] = mapped_column(String)
    # 年份
    year: Mapped[Optional[str]] = mapped_column(String)
    # 媒体数据源与原生ID
    media_source: Mapped[Optional[str]] = mapped_column(String, index=True)
    media_id: Mapped[Optional[str]] = mapped_column(String, index=True)
    # 路径
    path: Mapped[Optional[str]] = mapped_column(String)
    # 季集
    seasoninfo: Mapped[Optional[Any]] = mapped_column(JSON, default=dict)
    # 备注
    note: Mapped[Optional[Any]] = mapped_column(JSON)
    # 同步时间
    lst_mod_date: Mapped[Optional[str]] = mapped_column(String, default=datetime.now().strftime("%Y-%m-%d %H:%M:%S"))

    __table_args__ = (
        media_identity_constraint("mediaserveritem"),
        Index('ux_mediaserveritem_server_item_id', 'server', 'item_id', unique=True),
        Index(
            'ix_mediaserveritem_media_identity_type',
            'media_source', 'media_id', 'item_type',
        ),
    )

    @classmethod
    def get_by_itemid(cls, db: Session, item_id: str):
        return db.execute(select(cls).where(cls.item_id == item_id)).scalars().first()

    @classmethod
    def get_by_server_itemid(cls, db: Session, server: str, item_id: str):
        return db.execute(
            select(cls).where(cls.server == server, cls.item_id == item_id)
        ).scalars().first()

    @classmethod
    def empty(cls, db: Session, server: Optional[str] = None):
        """在调用方事务中暂存媒体服务器条目清空操作。"""
        statement = delete(cls)
        if server is not None:
            statement = statement.where(cls.server == server)
        db.execute(statement, execution_options={"synchronize_session": False})

    @classmethod
    def delete_stale(cls, db: Session, server: str, sync_time: str):
        """在调用方事务中删除本轮同步未更新的条目。"""
        return execute_dml(
            db,
            delete(cls).where(
                cls.server == server,
                or_(cls.lst_mod_date.is_(None), cls.lst_mod_date != sync_time),
            ),
            execution_options={"synchronize_session": False},
        )

    @classmethod
    def delete_excluded_servers(cls, db: Session, servers: List[str]):
        """在调用方事务中删除不属于启用服务器的条目。"""
        statement = delete(cls)
        if servers:
            statement = statement.where(
                or_(cls.server.is_(None), ~cls.server.in_(servers))
            )
        return execute_dml(
            db, statement, execution_options={"synchronize_session": False}
        )

    @classmethod
    def exist_by_media_identity(
            cls, db: Session, media_source: MediaSource, media_id: str, mtype: str,
    ):
        """按规范媒体身份和类型查询媒体服务器条目。"""
        return db.execute(select(cls).where(
            cls.media_source == str(media_source),
            cls.media_id == str(media_id),
            cls.item_type == mtype,
        )).scalars().first()

    @classmethod
    def exists_by_title(cls, db: Session, title: str, mtype: str, year: str):
        statement = select(cls).where(cls.title == title)
        if mtype:
            statement = statement.where(cls.item_type == mtype)
        if year:
            statement = statement.where(cls.year == str(year))
        return db.execute(statement).scalars().first()

    @classmethod
    async def async_get_by_itemid(cls, db: AsyncSession, item_id: str):
        result = await db.execute(select(cls).filter(cls.item_id == item_id))
        return result.scalars().first()

    @classmethod
    async def async_exist_by_media_identity(
            cls, db: AsyncSession, media_source: MediaSource, media_id: str, mtype: str,
    ):
        """异步按规范媒体身份和类型查询媒体服务器条目。"""
        result = await db.execute(select(cls).filter(
            cls.media_source == str(media_source),
            cls.media_id == str(media_id),
            cls.item_type == mtype,
        ))
        return result.scalars().first()

    @classmethod
    async def async_exists_by_title(cls, db: AsyncSession, title: str, mtype: str, year: str):
        if not mtype and not year:
            result = await db.execute(select(cls).filter(cls.title == title))
        elif not year:
            result = await db.execute(select(cls).filter(cls.title == title,
                                                         cls.item_type == mtype))
        elif not mtype:
            result = await db.execute(select(cls).filter(cls.title == title,
                                                         cls.year == str(year)))
        else:
            result = await db.execute(select(cls).filter(cls.title == title,
                                                     cls.item_type == mtype,
                                                     cls.year == str(year)))
        return result.scalars().first()
