from pathlib import Path
from typing import Any, List, Optional, Annotated

from fastapi import Depends
from fastapi.concurrency import run_in_threadpool

from app.schemas.dashboard import DashboardMemoryInfo as _SchemaDashboardMemoryInfo
from app.schemas.dashboard import DashboardSystemInfo as _SchemaDashboardSystemInfo
from app.schemas.dashboard import DownloaderInfo as _SchemaDownloaderInfo
from app.schemas.dashboard import ProcessInfo as _SchemaProcessInfo
from app.schemas.dashboard import ScheduleInfo as _SchemaScheduleInfo
from app.schemas.dashboard import ScheduleProgress as _SchemaScheduleProgress
from app.schemas.dashboard import Statistic as _SchemaStatistic
from app.schemas.dashboard import Storage as _SchemaStorage
from app.schemas.response import Response as _SchemaResponse
from app.api.response import ResponseAPIRouter
from app.chain.dashboard import DashboardChain
from app.chain.storage import StorageChain
from app.api.context import get_api_runtime_config, resolve_api_runtime_config
from app.application.configuration import ApiRuntimeConfig
from app.adapters.web.security.access import verify_apitoken
from app.api.dependencies.auth import get_current_active_superuser
from app.api.dependencies.history import get_dashboard_query_service
from app.application.dashboard import DashboardQueryService
from app.schemas.types import StorageAction
from app.application.directory import DirectoryHelper
from app.application.scheduling import Scheduler
from app.adapters.system.host import SystemUtils

router = ResponseAPIRouter()


def _build_storage() -> _SchemaStorage:
    """
    构建本地存储空间信息。
    """
    total, available = 0, 0
    dirs = DirectoryHelper().get_dirs()
    if not dirs:
        return _SchemaStorage(total_storage=total, used_storage=total - available)
    # 下载目录按 storage、媒体库目录按 library_storage 汇总存储集合，
    # 用 set 去重存储名，避免同一存储被重复统计；
    # 各存储的 usage 内部已按磁盘（st_dev / Btrfs FSID）去重，相同磁盘的不同目录不会重复累加。
    storages = set(
        [d.storage for d in dirs if d.download_path and d.storage]
        + [d.library_storage for d in dirs if d.library_path and d.library_storage]
    )
    for _storage in storages:
        _result = StorageChain().manage_storage(storage=_storage, action=StorageAction.USAGE.value)
        _usage = _result.get("data") if _result.get("success") else None
        if _usage:
            total += _usage.get("total") or 0
            available += _usage.get("available") or 0
    return _SchemaStorage(total_storage=total, used_storage=total - available)


def _build_downloader(
    name: Optional[str] = None,
    *,
    btrfs_fsid_dedup: bool = False,
) -> _SchemaDownloaderInfo:
    """
    构建下载器统计信息。
    """
    # 下载目录空间
    download_dirs = DirectoryHelper().get_local_download_dirs()
    _, free_space = SystemUtils.space_usage(
        [Path(d.download_path) for d in download_dirs],
        btrfs_fsid_dedup=btrfs_fsid_dedup,
    )
    # 下载器信息
    downloader_info = _SchemaDownloaderInfo()
    transfer_infos = DashboardChain().downloader_info(name)
    if transfer_infos:
        for transfer_info in transfer_infos:
            downloader_info.download_speed += transfer_info.download_speed
            downloader_info.upload_speed += transfer_info.upload_speed
            downloader_info.download_size += transfer_info.download_size
            downloader_info.upload_size += transfer_info.upload_size
        downloader_info.free_space = free_space
    return downloader_info


@router.get("/statistic", summary="媒体数量统计", response_model=_SchemaStatistic)
def statistic(
    name: Optional[str] = None,
    service: DashboardQueryService = Depends(get_dashboard_query_service),
    _: Any = Depends(get_current_active_superuser),
) -> Any:
    """
    查询媒体数量统计信息
    """
    return service.statistic(name)


@router.get(
    "/statistic2", summary="媒体数量统计（API_TOKEN）", response_model=_SchemaStatistic
)
def statistic2(
    _: Annotated[str, Depends(verify_apitoken)],
    service: DashboardQueryService = Depends(get_dashboard_query_service),
) -> Any:
    """
    查询媒体数量统计信息 API_TOKEN认证（?token=xxx）
    """
    return service.statistic()


@router.get("/storage", summary="本地存储空间", response_model=_SchemaStorage)
def storage(_: Any = Depends(get_current_active_superuser)) -> Any:
    """
    查询本地存储空间信息
    """
    return _build_storage()


@router.get(
    "/storage2", summary="本地存储空间（API_TOKEN）", response_model=_SchemaStorage
)
def storage2(_: Annotated[str, Depends(verify_apitoken)]) -> Any:
    """
    查询本地存储空间信息 API_TOKEN认证（?token=xxx）
    """
    return _build_storage()


@router.get("/processes", summary="进程信息", response_model=List[_SchemaProcessInfo])
def processes(_: Any = Depends(get_current_active_superuser)) -> Any:
    """
    查询进程信息
    """
    return SystemUtils.processes()


@router.get("/system", summary="系统摘要信息", response_model=_SchemaDashboardSystemInfo)
def system_info(_: Any = Depends(get_current_active_superuser)) -> Any:
    """
    查询仪表板系统摘要信息
    """
    return SystemUtils.dashboard_system_info()


@router.get("/downloader", summary="下载器信息", response_model=_SchemaDownloaderInfo)
def downloader(
    name: Optional[str] = None,
    runtime_config: ApiRuntimeConfig = Depends(get_api_runtime_config),
    _: Any = Depends(get_current_active_superuser),
) -> Any:
    """
    查询下载器信息
    """
    runtime_config = resolve_api_runtime_config(runtime_config)
    return _build_downloader(
        name,
        btrfs_fsid_dedup=runtime_config.btrfs_fsid_dedup,
    )


@router.get(
    "/downloader2",
    summary="下载器信息（API_TOKEN）",
    response_model=_SchemaDownloaderInfo,
)
def downloader2(
    _: Annotated[str, Depends(verify_apitoken)],
    runtime_config: ApiRuntimeConfig = Depends(get_api_runtime_config),
) -> Any:
    """
    查询下载器信息 API_TOKEN认证（?token=xxx）
    """
    runtime_config = resolve_api_runtime_config(runtime_config)
    return _build_downloader(
        btrfs_fsid_dedup=runtime_config.btrfs_fsid_dedup,
    )


@router.get("/schedule", summary="后台服务", response_model=List[_SchemaScheduleInfo])
async def schedule(_: Any = Depends(get_current_active_superuser)) -> Any:
    """
    查询后台服务信息
    """
    # 同步 list() 内含同步进度读取，放到线程池执行避免阻塞事件循环
    return await run_in_threadpool(Scheduler().list)


@router.get(
    "/schedule/{job_id}/progress",
    summary="后台服务进度",
    response_model=_SchemaResponse[_SchemaScheduleProgress],
)
async def schedule_progress(
    job_id: str, _: Any = Depends(get_current_active_superuser)
) -> Any:
    """
    查询指定后台服务的执行进度。
    """
    # 异步进度后端读取，避免同步 Redis 调用阻塞事件循环
    progress = await Scheduler().aget_progress(job_id)
    if not progress:
        return _SchemaResponse(success=False, message="后台服务不存在")
    return _SchemaResponse(success=True, data=progress.model_dump())


@router.get(
    "/schedule2",
    summary="后台服务（API_TOKEN）",
    response_model=List[_SchemaScheduleInfo],
)
async def schedule2(_: Annotated[str, Depends(verify_apitoken)]) -> Any:
    """
    查询下载器信息 API_TOKEN认证（?token=xxx）
    """
    # 同步 list() 内含同步进度读取，放到线程池执行避免阻塞事件循环
    return await run_in_threadpool(Scheduler().list)


@router.get(
    "/schedule2/{job_id}/progress",
    summary="后台服务进度（API_TOKEN）",
    response_model=_SchemaResponse[_SchemaScheduleProgress],
)
async def schedule_progress2(
    job_id: str, _: Annotated[str, Depends(verify_apitoken)]
) -> Any:
    """
    查询指定后台服务的执行进度 API_TOKEN认证（?token=xxx）
    """
    # 异步进度后端读取，避免同步 Redis 调用阻塞事件循环
    progress = await Scheduler().aget_progress(job_id)
    if not progress:
        return _SchemaResponse(success=False, message="后台服务不存在")
    return _SchemaResponse(success=True, data=progress.model_dump())


@router.get("/transfer", summary="文件整理统计", response_model=List[int])
async def transfer(
    days: Optional[int] = 7,
    service: DashboardQueryService = Depends(get_dashboard_query_service),
    _: Any = Depends(get_current_active_superuser),
) -> Any:
    """
    查询文件整理统计信息
    """
    return await service.transfer(days)


@router.get("/cpu", summary="获取当前CPU使用率", response_model=float)
def cpu(_: Any = Depends(get_current_active_superuser)) -> Any:
    """
    获取当前CPU使用率
    """
    return SystemUtils.cpu_usage()


@router.get("/cpu2", summary="获取当前CPU使用率（API_TOKEN）", response_model=float)
def cpu2(_: Annotated[str, Depends(verify_apitoken)]) -> Any:
    """
    获取当前CPU使用率 API_TOKEN认证（?token=xxx）
    """
    return SystemUtils.cpu_usage()


@router.get(
    "/memory",
    summary="获取当前应用与系统内存信息",
    response_model=_SchemaDashboardMemoryInfo,
)
def memory(_: Any = Depends(get_current_active_superuser)) -> Any:
    """
    获取当前应用与系统内存信息
    """
    return SystemUtils.memory_usage()


@router.get(
    "/memory2",
    summary="获取当前应用与系统内存信息（API_TOKEN）",
    response_model=_SchemaDashboardMemoryInfo,
)
def memory2(_: Annotated[str, Depends(verify_apitoken)]) -> Any:
    """
    获取当前应用与系统内存信息 API_TOKEN认证（?token=xxx）
    """
    return SystemUtils.memory_usage()


@router.get("/network", summary="获取当前网络流量", response_model=List[int])
def network(_: Any = Depends(get_current_active_superuser)) -> Any:
    """
    获取当前网络流量（上行和下行流量，单位：bytes/s）
    """
    return SystemUtils.network_usage()


@router.get(
    "/network2", summary="获取当前网络流量（API_TOKEN）", response_model=List[int]
)
def network2(_: Annotated[str, Depends(verify_apitoken)]) -> Any:
    """
    获取当前网络流量 API_TOKEN认证（?token=xxx）
    """
    return SystemUtils.network_usage()
