import time
from typing import Any, List, Optional

from sqlalchemy import delete as sqlalchemy_delete
from sqlalchemy.orm import Session

from app.db.base import DbOper
from app.db.models.transferhistory import TransferHistory
from app.schemas.types import MediaSource


class TransferHistoryOper(DbOper):
    """
    转移历史管理
    """

    def get(self, historyid: int) -> Optional[TransferHistory]:
        """
        获取转移历史
        :param historyid: 转移历史id
        """
        return self._execute_sync_query(
            lambda session: TransferHistory.get(session, historyid)
        )

    async def async_get(self, historyid: int) -> Optional[TransferHistory]:
        """
        异步获取转移历史。
        """
        return await self._execute_async_query(
            lambda session: TransferHistory.async_get(session, historyid)
        )

    async def async_list_by_title(
        self,
        title: str,
        page: int = 1,
        count: int = 30,
        status: Optional[bool] = None,
        wildcard: bool = False,
    ) -> List[TransferHistory]:
        """
        异步按标题分页查询转移记录。
        """
        return await self._execute_async_query(
            lambda session: TransferHistory.async_list_by_title(
                session,
                title=title,
                page=page,
                count=count,
                status=status,
                wildcard=wildcard,
            )
        )

    async def async_list_by_page(
        self,
        page: int = 1,
        count: int = 30,
        status: Optional[bool] = None,
    ) -> List[TransferHistory]:
        """
        异步分页查询转移记录。
        """
        return await self._execute_async_query(
            lambda session: TransferHistory.async_list_by_page(
                session, page=page, count=count, status=status
            )
        )

    async def async_count(self, status: Optional[bool] = None) -> Optional[int]:
        """
        异步统计转移记录数量。
        """
        return await self._execute_async_query(
            lambda session: TransferHistory.async_count(session, status=status)
        )

    async def async_count_by_title(
        self,
        title: str,
        status: Optional[bool] = None,
        wildcard: bool = False,
    ) -> Optional[int]:
        """
        异步按标题统计转移记录数量。
        """
        return await self._execute_async_query(
            lambda session: TransferHistory.async_count_by_title(
                session,
                title=title,
                status=status,
                wildcard=wildcard,
            )
        )

    def get_by_title(self, title: str) -> List[TransferHistory]:
        """
        按标题查询转移记录
        :param title: 数据key
        """
        return self._execute_sync_query(
            lambda session: TransferHistory.list_by_title(session, title)
        )

    def get_by_src(
            self, src: str, storage: Optional[str] = None
    ) -> Optional[TransferHistory]:
        """
        按源查询转移记录
        :param src: 数据key
        :param storage: 存储类型
        :return: 命中的整理记录，未命中时返回 None
        """
        return self._execute_sync_query(
            lambda session: TransferHistory.get_by_src(session, src, storage)
        )

    def get_success_by_src(
            self, src: str, storage: Optional[str] = None
    ) -> Optional[TransferHistory]:
        """
        按源查询成功的转移记录，源路径原样精确匹配
        :param src: 数据key
        :param storage: 存储类型
        :return: 命中的成功整理记录，未命中时返回 None
        """
        return self._execute_sync_query(
            lambda session: TransferHistory.get_success_by_src(
                session, src, storage
            )
        )

    def get_by_dest(
            self, dest: str, storage: Optional[str] = None
    ) -> Optional[TransferHistory]:
        """
        按转移路径查询转移记录
        :param dest: 数据key
        :param storage: 存储类型
        """
        return self._execute_sync_query(
            lambda session: TransferHistory.get_by_dest(session, dest, storage)
        )

    def list_success_by_src(
            self,
            src: str,
            storage: Optional[str] = None,
            recursive: bool = False,
    ) -> List[TransferHistory]:
        """
        按源路径查询成功整理记录。

        :param src: 源路径
        :param storage: 源存储类型
        :param recursive: 是否递归匹配目录子项
        :return: 命中的成功整理记录
        """
        return self._execute_sync_query(
            lambda session: TransferHistory.list_success_by_src(
                session,
                src=src,
                storage=storage,
                recursive=recursive,
            )
        )

    def list_success_move_by_dest(
            self,
            dest: str,
            storage: Optional[str] = None,
            recursive: bool = False,
    ) -> List[TransferHistory]:
        """
        按目标路径查询成功移动记录。

        :param dest: 目标路径
        :param storage: 目标存储类型
        :param recursive: 是否递归匹配目录子项
        :return: 命中的成功移动记录
        """
        return self._execute_sync_query(
            lambda session: TransferHistory.list_success_move_by_dest(
                session,
                dest=dest,
                storage=storage,
                recursive=recursive,
            )
        )

    def list_by_hash(self, download_hash: str) -> List[TransferHistory]:
        """
        按种子hash查询转移记录
        :param download_hash: 种子hash
        """
        return self._execute_sync_query(
            lambda session: TransferHistory.list_by_hash(session, download_hash)
        )

    def add(self, **kwargs):
        """
        新增转移历史
        """
        kwargs.update({
            "date": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        })
        self._stage_create(TransferHistory(**kwargs))

    def statistic(self, days: int = 7) -> List[Any]:
        """
        统计最近days天的下载历史数量
        """
        return self._execute_sync_query(
            lambda session: TransferHistory.statistic(session, days)
        )

    async def async_statistic(self, days: int = 7) -> List[Any]:
        """异步统计最近若干天的整理历史数量。"""
        return await self._execute_async_query(
            lambda session: TransferHistory.async_statistic(session, days)
        )

    def monthly_media_statistics(self) -> tuple[int, int, int, int]:
        """统计本月成功整理的电影、剧集、单集和音乐数量。"""
        return self._execute_sync_query(
            TransferHistory.monthly_media_statistics
        )

    def get_by(self, title: Optional[str] = None, year: Optional[str] = None, mtype: Optional[str] = None,
               season: Optional[str] = None, episode: Optional[str] = None,
               media_source: Optional[MediaSource] = None, media_id: Optional[str] = None,
               dest: Optional[str] = None) -> List[TransferHistory]:
        """
        按类型、标题、年份、季集查询转移记录
        """
        return self._execute_sync_query(
            lambda session: TransferHistory.list_by(
                db=session,
                mtype=mtype,
                title=title,
                dest=dest,
                year=year,
                season=season,
                episode=episode,
                media_source=media_source,
                media_id=media_id,
            )
        )

    def get_by_media_identity(
            self, media_source: MediaSource, media_id: str,
            mtype: Optional[str] = None,
    ) -> Optional[TransferHistory]:
        """按规范媒体身份和类型查询整理记录。"""
        return self._execute_sync_query(
            lambda session: TransferHistory.get_by_media_identity(
                db=session,
                media_source=media_source,
                media_id=media_id,
                mtype=mtype,
            )
        )

    def delete(self, historyid):
        """
        删除转移记录
        """
        self._stage_delete(TransferHistory, historyid)

    def stage_delete(self, historyid: int) -> None:
        """暂存整理记录删除，事务由调用方统一提交。"""
        self._db.execute(
            sqlalchemy_delete(TransferHistory).where(
                TransferHistory.id == historyid
            )
        )

    def stage_truncate(self) -> None:
        """暂存全部整理记录删除，由请求级事务统一提交。"""
        self._db.execute(sqlalchemy_delete(TransferHistory))

    async def async_delete(self, historyid):
        """
        异步删除转移记录。
        """
        await self._stage_async_delete(TransferHistory, historyid)

    def truncate(self):
        """
        清空转移记录
        """
        self._stage_truncate(TransferHistory)

    def add_force(self, **kwargs) -> Optional[TransferHistory]:
        """
        新增转移历史，并以同源存储的记录为准替换旧记录。
        """
        # 文件项的默认存储是 local；归一化旧调用传入的 None，确保运行时语义与
        # (src, src_storage) 唯一索引一致。
        kwargs["src_storage"] = kwargs.get("src_storage") or "local"
        # 旧记录的清理交给 replace_by_src 按 (src, src_storage) 处理：
        # 仅按 src 删除会连带删掉其他存储下同路径的记录。
        kwargs.update({
            "date": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        })
        def stage(session: Session) -> Optional[TransferHistory]:
            """在同一事务替换记录并返回兼容查询投影。"""
            TransferHistory.replace_by_src(session, **kwargs)
            return TransferHistory.get_by_src(
                session,
                kwargs.get("src"),
                kwargs["src_storage"],
            )

        # 保持 add_force 的既有返回契约：返回可被调用方安全读取字段的查询结果，
        # 而非事务提交后可能已脱离会话的新建实例。
        return self._execute_sync_write(stage)

    def stage_replace_by_src(self, **kwargs) -> TransferHistory:
        """在调用方事务内按源路径替换整理历史并返回已分配 ID 的新记录。"""
        if not isinstance(self._db, Session):
            raise RuntimeError("整理历史事务写入需要调用方提供同步 Session")
        kwargs["src_storage"] = kwargs.get("src_storage") or "local"
        kwargs["date"] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        self._db.execute(
            sqlalchemy_delete(TransferHistory).where(
                TransferHistory.src == kwargs.get("src"),
                TransferHistory.src_storage == kwargs["src_storage"],
            )
        )
        self._db.flush()
        history = TransferHistory(**kwargs)
        self._db.add(history)
        self._db.flush()
        return history

    def update_download_hash(self, historyid, download_hash):
        """
        补充转移记录download_hash
        """
        self._execute_sync_write(
            lambda session: TransferHistory.update_download_hash(
                session,
                historyid,
                download_hash,
            )
        )

    def list_by_date(self, date: str) -> List[TransferHistory]:
        """
        查询某时间之后的转移历史
        :param date: 日期
        """
        return self._execute_sync_query(
            lambda session: TransferHistory.list_by_date(session, date)
        )
