"""
网盘存储通用管理契约（storage_manage）守护测试

验证与通知渠道一致的通用模式：
1. 链层 manage_storage 只透明转发存储标识、动作与参数，不做任何存储特定处理
2. 模块按存储标识路由，动作语义与参数解释封闭在模块内
3. 端点层的 ManageRequest 通用请求结构：target + action + params
"""
from types import SimpleNamespace
from typing import Any, Dict

import pytest

from app import schemas
from app.chain.storage import StorageChain
from app.modules.filemanager import FileManagerModule


class _FakeStorageOper:
    """记录管理动作调用情况的假存储实现"""

    schema = SimpleNamespace(value="fakestore")
    calls = []

    def set_config(self, conf):
        _FakeStorageOper.calls.append(("set_config", conf))

    def reset_config(self):
        _FakeStorageOper.calls.append(("reset_config", None))

    def usage(self):
        return schemas.StorageUsage(total=100, available=40)

    def support_transtype(self):
        return {"move": True}

    def check_login(self, **kwargs):
        _FakeStorageOper.calls.append(("check_login", kwargs))
        return {"status": True}, None


@pytest.fixture
def module(monkeypatch):
    _FakeStorageOper.calls.clear()
    module = FileManagerModule()
    monkeypatch.setattr(module, "_support_storages", ["fakestore"])
    monkeypatch.setattr(module, "_storage_schemas", [_FakeStorageOper])
    return module


def test_manage_request_schema():
    """ManageRequest 仅定义目标标识、动作标识与透传参数，无任何特定领域字段。"""
    request = schemas.ManageRequest(target="fakestore", action="usage")
    assert request.target == "fakestore"
    assert request.action == "usage"
    assert request.params == {}


def test_storage_chain_forwards_target_action_and_params(monkeypatch):
    """链层按 storage_manage 契约原样透传，不引入存储特定逻辑。"""
    captured = {}

    def fake_run_module(self, method, **kwargs):
        captured.update(method=method, kwargs=kwargs)
        return {"success": True, "data": {"total": 100}}

    monkeypatch.setattr(StorageChain, "run_module", fake_run_module)
    chain = StorageChain.__new__(StorageChain)
    result = chain.manage_storage(storage="fakestore", action="usage", extra="value")

    assert captured["method"] == "storage_manage"
    assert captured["kwargs"] == {"storage": "fakestore", "action": "usage", "extra": "value"}
    assert result["success"] is True


def test_storage_chain_reports_missing_module(monkeypatch):
    """无模块实现 storage_manage 时返回统一失败结构。"""
    monkeypatch.setattr(StorageChain, "run_module", lambda self, method, **kwargs: None)
    chain = StorageChain.__new__(StorageChain)
    result = chain.manage_storage(storage="unknown", action="usage")
    assert result["success"] is False
    assert result["message"]


def test_storage_manage_rejects_unknown_action(module):
    """动作词汇表之外的请求返回统一错误结构。"""
    result = module.storage_manage(storage="fakestore", action="not_an_action")
    assert result["success"] is False
    assert "不支持" in result["message"]


def test_storage_manage_rejects_unknown_storage(module):
    """未注册的存储标识直接返回错误，不进入动作分发。"""
    result = module.storage_manage(storage="unknown_store", action="usage")
    assert result["success"] is False
    assert "不支持的存储类型" in result["message"]


def test_storage_manage_save_config_passes_conf_through(module):
    """save_config 动作将 params.conf 原样交给存储实现持久化。"""
    result = module.storage_manage(
        storage="fakestore", action="save_config", conf={"token": "abc"}
    )
    assert result["success"] is True
    assert ("set_config", {"token": "abc"}) in _FakeStorageOper.calls


def test_storage_manage_usage_returns_oper_data(module):
    """usage 动作返回纯 dict 用量数据，空结果同样成功。"""
    result = module.storage_manage(storage="fakestore", action="usage")
    assert result["success"] is True
    assert result["data"] == {"total": 100.0, "available": 40.0}


def test_storage_manage_usage_data_passes_open_mapping_response(module):
    """用量数据必须能透过通用响应 Response[Dict[str, Any]] 的开放映射校验。

    回归守护：存储实现返回 pydantic 模型时若未转 dict，
    端点响应校验会直接 500，前端存储页整体报未知错误。
    """
    result = module.storage_manage(storage="fakestore", action="usage")
    response = schemas.Response[Dict[str, Any]](
        success=result["success"], message=result.get("message"), data=result["data"]
    )
    assert response.data == {"total": 100.0, "available": 40.0}


def test_storage_manage_usage_defaults_when_oper_returns_none(module, monkeypatch):
    """存储实现查不到用量时返回成功的默认空结构而非业务失败。"""
    monkeypatch.setattr(_FakeStorageOper, "usage", lambda self: None)
    result = module.storage_manage(storage="fakestore", action="usage")
    assert result["success"] is True
    assert result["data"] == {"total": 0.0, "available": 0.0}


def test_storage_manage_support_transtype(module):
    """support_transtype 动作返回值包装为 transtype，与旧契约结构一致。"""
    result = module.storage_manage(storage="fakestore", action="support_transtype")
    assert result["success"] is True
    assert result["data"] == {"transtype": {"move": True}}


def test_storage_manage_support_transtype_empty_still_succeeds(module, monkeypatch):
    """存储不支持任何整理方式时返回成功空结构，避免前端把空结果当业务失败。"""
    monkeypatch.setattr(_FakeStorageOper, "support_transtype", lambda self: {})
    result = module.storage_manage(storage="fakestore", action="support_transtype")
    assert result["success"] is True
    assert result["data"] == {"transtype": {}}


def test_storage_manage_login_action_forwards_params(module):
    """登录类动作透传表单参数并归一化元组返回值。"""
    result = module.storage_manage(storage="fakestore", action="check_login", ck="ck1", t="t1")
    assert result["success"] is True
    assert result["data"] == {"status": True}
    assert ("check_login", {"ck": "ck1", "t": "t1"}) in _FakeStorageOper.calls


def test_storage_manage_reports_unsupported_login_action(module):
    """存储实现未提供对应登录方法时返回明确失败信息。"""
    result = module.storage_manage(storage="fakestore", action="generate_qrcode")
    assert result["success"] is False
    assert "不支持" in result["message"]
