from typing import List, Any, Dict, Optional

from fastapi import Depends, HTTPException
from typing import Annotated

from app.schemas.common import JsonObject as _SchemaJsonObject
from app.schemas.response import Response as _SchemaResponse
from app.schemas.site import SiteAuth as _SchemaSiteAuth
from app.schemas.site import SiteCategory as _SchemaSiteCategory
from app.schemas.site import SiteCookieUpdate as _SchemaSiteCookieUpdate
from app.schemas.site import SiteIconData as _SchemaSiteIconData
from app.schemas.site import SiteMappingData as _SchemaSiteMappingData
from app.schemas.site import SiteStatistic as _SchemaSiteStatistic
from app.schemas.site import SiteUserData as _SchemaSiteUserData
from app.schemas.system import TorrentInfo as _SchemaTorrentInfo
from app.schemas.token import TokenPayload as _SchemaTokenPayload
from app.schemas.workflow import Site as _SchemaSite
from app.api.response import ResponseAPIRouter
from app.application.site.mutation import SiteMutationCommand
from app.application.site.query import SiteQueryService
from app.api.endpoints.plugin import register_plugin_api
from app.chain.site import SiteChain
from app.chain.torrents import TorrentsChain
from app.application.commands import init_commands
from app.application.plugin.runtime import get_plugin_manager as PluginManager
from app.adapters.web.security.access import verify_token
from app.api.principal import ApiPrincipal
from app.application.configuration import get_configured_system_config
from app.api.dependencies.auth import (
    get_current_active_manage_user,
    get_current_active_manage_user_async,
    get_current_active_superuser,
    get_current_active_superuser_async,
)
from app.api.dependencies.site import (
    get_site_mutation_command,
    get_site_query_service,
    get_site_sync_query_service,
)
from app.application.site.sites import SitesHelper  # pylint: disable=import-error,no-name-in-module
from app.runtime.log import logger
from app.application.scheduling import Scheduler
from app.schemas.types import SystemConfigKey, MediaType
from app.domain import site as site_rules
from app.api.context import get_background_task_registry, resolve_background_task_registry
from app.runtime.tasks import TaskRegistry

router = ResponseAPIRouter()


def _indexer_supports_media_type(indexer: dict, media_type: MediaType) -> bool:
    """
    判断站点索引器是否支持指定媒体类型。

    :param indexer: 站点索引器配置
    :param media_type: 待搜索的媒体类型
    :return: 是否应在该媒体类型的站点选择列表中显示
    """
    declared_media_type = indexer.get("media_type")
    if isinstance(declared_media_type, MediaType):
        site_media_type = declared_media_type
    elif isinstance(declared_media_type, str):
        site_media_type = MediaType.from_agent(declared_media_type)
    else:
        site_media_type = None
    if site_media_type:
        return site_media_type == media_type

    categories = indexer.get("category") or {}
    if not isinstance(categories, dict):
        return media_type != MediaType.MUSIC

    category_key = media_type.to_agent()
    if media_type == MediaType.MUSIC:
        return bool(categories.get(category_key))

    declared_category_keys = {
        item.to_agent()
        for item in (MediaType.MOVIE, MediaType.TV, MediaType.MUSIC)
        if categories.get(item.to_agent())
    }
    if declared_category_keys:
        return category_key in declared_category_keys
    return True


@router.get("/", summary="所有站点", response_model=List[_SchemaSite])
async def read_sites(
    query: SiteQueryService = Depends(get_site_query_service),
    _: ApiPrincipal = Depends(get_current_active_manage_user_async),
) -> List[dict]:
    """
    获取站点列表
    """
    return await query.list_ordered()


@router.get(
    "/media/{media_type}",
    summary="按媒体类型获取可搜索站点",
    response_model=List[_SchemaSite],
)
async def read_sites_by_media_type(
    media_type: str,
    query: SiteQueryService = Depends(get_site_query_service),
    _: ApiPrincipal = Depends(get_current_active_manage_user_async),
) -> List[_SchemaSite]:
    """
    获取支持指定媒体类型的已配置启用站点。

    :param media_type: Agent 媒体类型名称或中文媒体类型
    :param query: 站点查询服务
    :return: 按优先级排序的可搜索站点
    """
    target_media_type = MediaType.from_agent(media_type)
    if not target_media_type:
        try:
            target_media_type = MediaType(media_type)
        except ValueError as error:
            raise HTTPException(status_code=400, detail="不支持的媒体类型") from error
    if target_media_type not in (MediaType.MOVIE, MediaType.TV, MediaType.MUSIC):
        raise HTTPException(status_code=400, detail="不支持的媒体类型")

    supported_ids = set()
    supported_domains = set()
    for indexer in await SitesHelper().async_get_indexers() or []:
        if not _indexer_supports_media_type(indexer, target_media_type):
            continue
        if indexer.get("id") is not None:
            supported_ids.add(str(indexer.get("id")))
        domain = site_rules.extract_domain(indexer.get("domain"))
        if domain:
            supported_domains.add(domain)

    sites = await query.list_ordered()
    return [
        site
        for site in sites
        if site.is_active
        and (str(site.id) in supported_ids or site.domain in supported_domains)
    ]


@router.post("/", summary="新增站点", response_model=_SchemaResponse[None])
async def add_site(
    *,
    site_in: _SchemaSite,
    command: SiteMutationCommand = Depends(get_site_mutation_command),
    _: ApiPrincipal = Depends(get_current_active_manage_user_async),
) -> Any:
    """
    新增站点
    """
    result = await command.create(site_in.model_dump())
    return _SchemaResponse(success=result.success, message=result.message)


@router.put("/", summary="更新站点", response_model=_SchemaResponse[None])
async def update_site(
    *,
    site_in: _SchemaSite,
    command: SiteMutationCommand = Depends(get_site_mutation_command),
    _: ApiPrincipal = Depends(get_current_active_manage_user_async),
) -> Any:
    """
    更新站点信息
    """
    result = await command.update(site_in.model_dump())
    return _SchemaResponse(success=result.success, message=result.message)


@router.get("/cookiecloud", summary="CookieCloud同步", response_model=_SchemaResponse[None])
async def cookie_cloud_sync(
    task_registry: Annotated[TaskRegistry, Depends(get_background_task_registry)],
    _: ApiPrincipal = Depends(get_current_active_superuser_async),
) -> Any:
    """
    运行CookieCloud同步站点信息
    """
    resolve_background_task_registry(task_registry).create_sync(
        Scheduler().start, job_id="cookiecloud", owner="api.site.cookiecloud_sync"
    )
    return _SchemaResponse(success=True, message="CookieCloud同步任务已启动！")


@router.get("/reset", summary="重置站点", response_model=_SchemaResponse[None])
async def reset(
    task_registry: Annotated[TaskRegistry, Depends(get_background_task_registry)],
    command: SiteMutationCommand = Depends(get_site_mutation_command),
    _: ApiPrincipal = Depends(get_current_active_superuser_async),
) -> Any:
    """
    清空所有站点数据并重新同步CookieCloud站点信息
    """
    result = await command.reset()
    await get_configured_system_config().async_set(SystemConfigKey.IndexerSites, [])
    await get_configured_system_config().async_set(SystemConfigKey.RssSites, [])
    resolve_background_task_registry(task_registry).create_sync(
        Scheduler().start,
        job_id="cookiecloud",
        owner="api.site.reset",
        manual=True,
    )
    return _SchemaResponse(success=result.success, message="站点已重置！")


@router.post(
    "/priorities", summary="批量更新站点优先级", response_model=_SchemaResponse[None]
)
async def update_sites_priority(
    priorities: List[dict],
    command: SiteMutationCommand = Depends(get_site_mutation_command),
    _: ApiPrincipal = Depends(get_current_active_manage_user_async),
) -> Any:
    """
    批量更新站点优先级
    """
    result = await command.update_priorities(priorities)
    return _SchemaResponse(success=result.success, message=result.message)


def _update_site_cookie(
    site_id: int,
    username: str,
    password: str,
    code: Optional[str],
    query: SiteQueryService,
) -> _SchemaResponse:
    """
    执行站点 Cookie 与 UA 更新。

    :param site_id: 站点编号
    :param username: 站点登录用户名
    :param password: 站点登录密码
    :param code: 二步验证码或密钥
    :param query: 站点查询服务
    :return: 更新结果
    """
    site_info = query.get_sync(site_id)
    if not site_info:
        raise HTTPException(
            status_code=404,
            detail=f"站点 {site_id} 不存在！",
        )
    logger.info(f"开始更新站点【{site_info.name}】Cookie&UA")
    state, message = SiteChain().update_cookie(
        site_info=site_info, username=username, password=password, two_step_code=code
    )
    if state:
        logger.info(f"站点【{site_info.name}】Cookie&UA更新成功")
    else:
        logger.error(f"站点【{site_info.name}】Cookie&UA更新失败：{message}")
    return _SchemaResponse(success=state, message=message)


@router.post(
    "/cookie/{site_id}", summary="更新站点Cookie&UA", response_model=_SchemaResponse[None]
)
def update_cookie_by_body(
    site_id: int,
    site_cookie_update: _SchemaSiteCookieUpdate,
    query: SiteQueryService = Depends(get_site_sync_query_service),
    _: ApiPrincipal = Depends(get_current_active_manage_user),
) -> Any:
    """
    使用请求体中的用户密码更新站点Cookie
    """
    return _update_site_cookie(
        site_id=site_id,
        username=site_cookie_update.username,
        password=site_cookie_update.password,
        code=site_cookie_update.code,
        query=query,
    )


@router.get(
    "/cookie/{site_id}", summary="更新站点Cookie&UA", response_model=_SchemaResponse[None]
)
def update_cookie(
    site_id: int,
    username: str,
    password: str,
    code: Optional[str] = None,
    query: SiteQueryService = Depends(get_site_sync_query_service),
    _: ApiPrincipal = Depends(get_current_active_manage_user),
) -> Any:
    """
    使用用户密码更新站点Cookie
    """
    return _update_site_cookie(
        site_id=site_id,
        username=username,
        password=password,
        code=code,
        query=query,
    )


@router.post(
    "/userdata/{site_id}",
    summary="更新站点用户数据",
    response_model=_SchemaResponse[_SchemaSiteUserData],
)
def refresh_userdata(
    site_id: int,
    query: SiteQueryService = Depends(get_site_sync_query_service),
    _: ApiPrincipal = Depends(get_current_active_manage_user),
) -> Any:
    """
    刷新站点用户数据
    """
    site = query.get_sync(site_id)
    if not site:
        raise HTTPException(
            status_code=404,
            detail=f"站点 {site_id} 不存在",
        )
    indexer = SitesHelper().get_indexer(site.domain)
    if not indexer:
        return _SchemaResponse(
            success=False, message="站点不支持索引或未通过用户认证！"
        )
    user_data = SiteChain().refresh_userdata(site=indexer) or {}
    return _SchemaResponse(success=True, data=user_data)


@router.get(
    "/userdata/latest",
    summary="查询所有站点最新用户数据",
    response_model=List[_SchemaSiteUserData],
)
async def read_userdata_latest(
    query: SiteQueryService = Depends(get_site_query_service),
    _: ApiPrincipal = Depends(get_current_active_manage_user_async),
) -> Any:
    """
    查询所有站点最新用户数据
    """
    return await query.userdata_latest()


@router.get(
    "/userdata/{site_id}",
    summary="查询某站点用户数据",
    response_model=_SchemaResponse[list[_SchemaSiteUserData]],
)
async def read_userdata(
    site_id: int,
    workdate: Optional[str] = None,
    query: SiteQueryService = Depends(get_site_query_service),
    _: ApiPrincipal = Depends(get_current_active_manage_user_async),
) -> Any:
    """
    查询站点用户数据
    """
    site = await query.get(site_id)
    if not site:
        raise HTTPException(
            status_code=404,
            detail=f"站点 {site_id} 不存在",
        )
    user_datas = await query.userdata(site.domain, workdate)
    if not user_datas:
        return _SchemaResponse(success=False, data=[])
    return _SchemaResponse(success=True, data=user_datas)


@router.get("/test/{site_id}", summary="连接测试", response_model=_SchemaResponse[None])
def test_site(
    site_id: int,
    query: SiteQueryService = Depends(get_site_sync_query_service),
    _: _SchemaTokenPayload = Depends(verify_token),
) -> Any:
    """
    测试站点是否可用
    """
    site = query.get_sync(site_id)
    if not site:
        raise HTTPException(
            status_code=404,
            detail=f"站点 {site_id} 不存在",
        )
    status, message = SiteChain().test(site.domain)
    return _SchemaResponse(success=status, message=message)


@router.get(
    "/icon/{site_id}",
    summary="站点图标",
    response_model=_SchemaResponse[_SchemaSiteIconData],
)
async def site_icon(
    site_id: int,
    query: SiteQueryService = Depends(get_site_query_service),
    _: _SchemaTokenPayload = Depends(verify_token),
) -> Any:
    """
    获取站点图标：base64或者url
    """
    site = await query.get(site_id)
    if not site:
        raise HTTPException(
            status_code=404,
            detail=f"站点 {site_id} 不存在",
        )
    icon = await query.icon(site.domain)
    if not icon:
        return _SchemaResponse(success=False, message="站点图标不存在！")
    return _SchemaResponse(success=True, data=icon.model_dump())


@router.get(
    "/category/{site_id}", summary="站点分类", response_model=List[_SchemaSiteCategory]
)
async def site_category(
    site_id: int,
    query: SiteQueryService = Depends(get_site_query_service),
    _: _SchemaTokenPayload = Depends(verify_token),
) -> Any:
    """
    获取站点分类
    """
    site = await query.get(site_id)
    if not site:
        raise HTTPException(
            status_code=404,
            detail=f"站点 {site_id} 不存在",
        )
    indexer = await SitesHelper().async_get_indexer(site.domain)
    if not indexer:
        raise HTTPException(
            status_code=404,
            detail=f"站点 {site.domain} 不支持",
        )
    category: Dict[str, List[dict]] = indexer.get("category") or []
    if not category:
        return []
    result = []
    for cats in category.values():
        for cat in cats:
            if cat not in result:
                result.append(cat)
    return result


@router.get(
    "/resource/{site_id}", summary="站点资源", response_model=List[_SchemaTorrentInfo]
)
async def site_resource(
    site_id: int,
    keyword: Optional[str] = None,
    mtype: Optional[str] = None,
    cat: Optional[str] = None,
    page: Optional[int] = 0,
    query: SiteQueryService = Depends(get_site_query_service),
    _: ApiPrincipal = Depends(get_current_active_manage_user_async),
) -> Any:
    """
    浏览站点资源
    """
    site = await query.get(site_id)
    if not site:
        raise HTTPException(
            status_code=404,
            detail=f"站点 {site_id} 不存在",
        )
    torrents = await TorrentsChain().async_browse(
        domain=site.domain,
        keyword=keyword,
        cat=cat,
        page=page,
        mtype=MediaType.from_agent(mtype) or MediaType(mtype) if mtype else None,
    )
    if not torrents:
        return []
    return [torrent.to_dict() for torrent in torrents]


@router.get("/domain/{site_url}", summary="站点详情", response_model=_SchemaSite)
async def read_site_by_domain(
    site_url: str,
    query: SiteQueryService = Depends(get_site_query_service),
    _: _SchemaTokenPayload = Depends(verify_token),
) -> Any:
    """
    通过域名获取站点信息
    """
    domain = site_rules.extract_domain(site_url)
    site = await query.get_by_domain(domain)
    if not site:
        raise HTTPException(
            status_code=404,
            detail=f"站点 {domain} 不存在",
        )
    return site


@router.get(
    "/statistic/{site_url}",
    summary="特定站点统计信息",
    response_model=_SchemaSiteStatistic,
)
async def read_statistic_by_domain(
    site_url: str,
    query: SiteQueryService = Depends(get_site_query_service),
    _: _SchemaTokenPayload = Depends(verify_token),
) -> Any:
    """
    通过域名获取站点统计信息
    """
    domain = site_rules.extract_domain(site_url)
    return await query.statistic(domain)


@router.get(
    "/statistic", summary="所有站点统计信息", response_model=List[_SchemaSiteStatistic]
)
async def read_statistics(
    query: SiteQueryService = Depends(get_site_query_service),
    _: _SchemaTokenPayload = Depends(verify_token),
) -> Any:
    """
    获取所有站点统计信息
    """
    return await query.statistics()


@router.get("/rss", summary="所有订阅站点", response_model=List[_SchemaSite])
async def read_rss_sites(
    query: SiteQueryService = Depends(get_site_query_service),
    _: _SchemaTokenPayload = Depends(verify_token),
) -> List[dict]:
    """
    获取站点列表
    """
    # 选中的rss站点
    selected_sites = get_configured_system_config().get(SystemConfigKey.RssSites) or []

    # 所有站点
    all_site = await query.list_ordered()
    if not selected_sites:
        return all_site

    # 选中的rss站点
    rss_sites = [site for site in all_site if site and site.id in selected_sites]
    return rss_sites


@router.get("/auth", summary="查询认证站点", response_model=_SchemaJsonObject)
async def read_auth_sites(_: _SchemaTokenPayload = Depends(verify_token)) -> dict:
    """
    获取可认证站点列表
    """
    return SitesHelper().get_authsites()


@router.post("/auth", summary="用户站点认证", response_model=_SchemaResponse[None])
def auth_site(
    auth_info: _SchemaSiteAuth, _: ApiPrincipal = Depends(get_current_active_superuser)
) -> Any:
    """
    用户站点认证
    """
    if not auth_info or not auth_info.site or not auth_info.params:
        return _SchemaResponse(success=False, message="请输入认证站点和认证参数")
    status, msg = SitesHelper().check_user(auth_info.site, auth_info.params)
    get_configured_system_config().set(SystemConfigKey.UserSiteAuthParams, auth_info.model_dump())
    # 认证成功后，重新初始化插件
    PluginManager().init_config()
    Scheduler().init_plugin_jobs()
    init_commands()
    register_plugin_api()
    return _SchemaResponse(success=status, message=msg)


@router.get(
    "/mapping",
    summary="获取站点域名到名称的映射",
    response_model=_SchemaResponse[_SchemaSiteMappingData],
)
async def site_mapping(
    query: SiteQueryService = Depends(get_site_query_service),
    _: ApiPrincipal = Depends(get_current_active_superuser_async),
):
    """
    获取站点域名到名称的映射关系
    """
    try:
        sites = await query.list_ordered()
        mapping = {}
        for site in sites:
            mapping[site.domain] = site.name
        return _SchemaResponse(success=True, data=mapping)
    except Exception as e:
        return _SchemaResponse(success=False, message=f"获取映射失败：{str(e)}")


@router.get(
    "/supporting",
    summary="获取支持的站点列表",
    response_model=_SchemaJsonObject,
)
async def support_sites(_: ApiPrincipal = Depends(get_current_active_superuser_async)):
    """
    获取支持的站点列表
    """
    return SitesHelper().get_indexsites()


@router.get("/{site_id}", summary="站点详情", response_model=_SchemaSite)
async def read_site(
    site_id: int,
    query: SiteQueryService = Depends(get_site_query_service),
    _: ApiPrincipal = Depends(get_current_active_manage_user_async),
) -> Any:
    """
    通过ID获取站点信息
    """
    site = await query.get(site_id)
    if not site:
        raise HTTPException(
            status_code=404,
            detail=f"站点 {site_id} 不存在",
        )
    return site


@router.delete("/{site_id}", summary="删除站点", response_model=_SchemaResponse[None])
async def delete_site(
    site_id: int,
    command: SiteMutationCommand = Depends(get_site_mutation_command),
    _: ApiPrincipal = Depends(get_current_active_manage_user_async),
) -> Any:
    """
    删除站点
    """
    result = await command.delete(site_id)
    return _SchemaResponse(success=result.success, message=result.message)
