from pathlib import Path
from types import SimpleNamespace
from unittest.mock import patch

from app.chain.transfer import TransferChain
from app.schemas import FileItem, TransferDirectoryConf
from app.application.transfer import TransferTask
from app.adapters.system.host import SystemUtils


def _make_task(
        storage: str = "local",
        download_path: str = "/mnt/clouddrive/downloads",
) -> TransferTask:
    return TransferTask(
        fileitem=FileItem(
            storage=storage,
            path=f"{download_path}/Test.Show.S01E01.mkv",
            type="file",
            name="Test.Show.S01E01.mkv",
        ),
        target_directory=TransferDirectoryConf(
            storage=storage,
            download_path=download_path,
        ),
    )


def test_enabled_cleanup_skips_filesystem_detection():
    """
    开关开启时应保持旧行为，且不产生额外文件系统检测。
    """
    with patch(
            "app.chain._transfer.SystemUtils.is_network_filesystem"
    ) as is_network_filesystem:
        should_delete = (
            TransferChain._should_delete_empty_source_directories(
                _make_task(),
                True,
                {},
            )
        )

    assert should_delete is True
    is_network_filesystem.assert_not_called()


def test_disabled_cleanup_keeps_mounted_local_source_directories():
    """
    开关关闭时应保留网络或 FUSE 挂载的本地源目录。
    """
    with patch(
            "app.chain._transfer.SystemUtils.is_network_filesystem",
            return_value=True,
    ) as is_network_filesystem:
        should_delete = (
            TransferChain._should_delete_empty_source_directories(
                _make_task(),
                False,
                {},
            )
        )

    assert should_delete is False
    is_network_filesystem.assert_called_once_with(
        Path("/mnt/clouddrive/downloads"), include_local_fuse=True
    )


def test_disabled_cleanup_still_deletes_ordinary_local_source_directories():
    """
    开关关闭时普通本地文件系统仍应删除空目录。
    """
    with patch(
            "app.chain._transfer.SystemUtils.is_network_filesystem",
            return_value=False,
    ):
        should_delete = (
            TransferChain._should_delete_empty_source_directories(
                _make_task(download_path="/downloads"),
                False,
                {},
            )
        )

    assert should_delete is True


def test_disabled_cleanup_does_not_change_remote_storage_cleanup():
    """
    开关关闭时非本地存储仍应执行原有空目录清理。
    """
    with patch(
            "app.chain._transfer.SystemUtils.is_network_filesystem"
    ) as is_network_filesystem:
        should_delete = (
            TransferChain._should_delete_empty_source_directories(
                _make_task(storage="alist", download_path="/downloads"),
                False,
                {},
            )
        )

    assert should_delete is True
    is_network_filesystem.assert_not_called()


def test_mounted_filesystem_detection_is_cached_by_source_directory():
    """
    同一源根目录的批量任务应只检测一次文件系统。
    """
    mounted_filesystem_cache = {}
    with patch(
            "app.chain._transfer.SystemUtils.is_network_filesystem",
            return_value=True,
    ) as is_network_filesystem:
        for _ in range(2):
            should_delete = (
                TransferChain._should_delete_empty_source_directories(
                    _make_task(),
                    False,
                    mounted_filesystem_cache,
                )
            )
            assert should_delete is False

    is_network_filesystem.assert_called_once_with(
        Path("/mnt/clouddrive/downloads"), include_local_fuse=True
    )


def test_cleanup_detection_includes_local_fuse_mounts():
    """
    空目录清理场景应将原本排除的本地 FUSE 文件系统视为挂载盘。
    """
    df_result = SimpleNamespace(
        returncode=0,
        stdout="Filesystem Type 1K-blocks Used Available Use% Mounted on\n"
               "shfs fuse.shfs 1 1 1 1% /mnt/user\n",
    )
    with patch("app.adapters.system.host.platform.system", return_value="Linux"), patch(
            "app.adapters.system.host.subprocess.run", return_value=df_result
    ):
        assert SystemUtils.is_network_filesystem(Path("/mnt/user")) is False
        assert SystemUtils.is_network_filesystem(
            Path("/mnt/user"), include_local_fuse=True
        ) is True
