from typing import Any, Optional
from datetime import datetime

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

from app.db.base import Base, get_id_column


class Site(Base):
    """
    站点表
    """
    id = get_id_column()
    # 站点名
    name: Mapped[str] = mapped_column(String, nullable=False)
    # 域名Key
    domain: Mapped[Optional[str]] = mapped_column(String, index=True)
    # 站点地址
    url: Mapped[str] = mapped_column(String, nullable=False)
    # 站点优先级
    pri: Mapped[Optional[int]] = mapped_column(Integer, default=1)
    # RSS地址，未启用
    rss: Mapped[Optional[str]] = mapped_column(String)
    # Cookie
    cookie: Mapped[Optional[str]] = mapped_column(String)
    # User-Agent
    ua: Mapped[Optional[str]] = mapped_column(String)
    # ApiKey
    apikey: Mapped[Optional[str]] = mapped_column(String)
    # Token
    token: Mapped[Optional[str]] = mapped_column(String)
    # 是否使用代理 0-否，1-是
    proxy: Mapped[Optional[int]] = mapped_column(Integer)
    # 过滤规则
    filter: Mapped[Optional[str]] = mapped_column(String)
    # 是否渲染
    render: Mapped[Optional[int]] = mapped_column(Integer)
    # 是否公开站点
    public: Mapped[Optional[int]] = mapped_column(Integer)
    # 附加信息
    note: Mapped[Optional[Any]] = mapped_column(JSON)
    # 流控单位周期
    limit_interval: Mapped[Optional[int]] = mapped_column(Integer, default=0)
    # 流控次数
    limit_count: Mapped[Optional[int]] = mapped_column(Integer, default=0)
    # 流控间隔
    limit_seconds: Mapped[Optional[int]] = mapped_column(Integer, default=0)
    # 超时时间
    timeout: Mapped[Optional[int]] = mapped_column(Integer, default=15)
    # 是否启用
    is_active: Mapped[Optional[bool]] = mapped_column(Boolean(), default=True)
    # 创建时间
    lst_mod_date: Mapped[Optional[str]] = mapped_column(String, default=datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    # 下载器
    downloader: Mapped[Optional[str]] = mapped_column(String)

    @classmethod
    def get_by_domain(cls, db: Session, domain: str):
        """在调用方 Session 中按域名查询站点。"""
        return db.execute(select(cls).where(cls.domain == domain)).scalars().first()

    @classmethod
    async def async_get_by_domain(
        cls,
        db: AsyncSession,
        domain: str,
    ):
        """在调用方 AsyncSession 中按域名查询站点。"""
        result = await db.execute(select(cls).where(cls.domain == domain))
        return result.scalar_one_or_none()

    @classmethod
    async def async_get_by_name(
        cls,
        db: AsyncSession,
        name: str,
    ):
        """在调用方 AsyncSession 中按站点名称查询。"""
        result = await db.execute(select(cls).where(cls.name == name))
        return result.scalar_one_or_none()

    @classmethod
    def get_actives(cls, db: Session):
        """在调用方 Session 中查询启用站点。"""
        return list(db.execute(
            select(cls).where(cls.is_active.is_(True))
        ).scalars().all())

    @classmethod
    async def async_get_actives(cls, db: AsyncSession):
        """在调用方 AsyncSession 中查询启用站点。"""
        result = await db.execute(select(cls).where(cls.is_active.is_(True)))
        return list(result.scalars().all())

    @classmethod
    def list_order_by_pri(cls, db: Session):
        """在调用方 Session 中按优先级升序查询站点。"""
        return list(db.execute(select(cls).order_by(cls.pri)).scalars().all())

    @classmethod
    async def async_list_order_by_pri(cls, db: AsyncSession):
        """在调用方 AsyncSession 中按优先级升序查询站点。"""
        result = await db.execute(select(cls).order_by(cls.pri))
        return list(result.scalars().all())

    @classmethod
    def get_domains_by_ids(
        cls,
        db: Session,
        ids: list[int],
    ):
        """在调用方 Session 中按 ID 查询域名。"""
        if not ids:
            return []
        return list(db.execute(
            select(cls.domain).where(cls.id.in_(ids))
        ).scalars().all())

    @classmethod
    def reset(cls, db: Session):
        """在调用方持有的同步事务中暂存清空操作。"""
        db.execute(delete(cls))

    @classmethod
    async def async_reset(cls, db: AsyncSession):
        """在调用方持有的异步事务中暂存清空操作。"""
        await db.execute(delete(cls))
