from __future__ import annotations

import importlib
from types import SimpleNamespace

from fastapi import FastAPI
from fastapi.testclient import TestClient

from server.utils.auth_middleware import get_admin_user, get_db, get_required_user

agent_router_module = importlib.import_module("server.routers.agent_router")


def _user(role: str = "admin"):
    uid = "admin" if role in {"admin", "superadmin"} else "user"
    return SimpleNamespace(uid=uid, role=role, department_id=1)


def _agent(slug: str, *, backend_id: str = "ChatbotAgent", is_subagent: bool = False):
    return SimpleNamespace(
        id=slug,
        slug=slug,
        name=slug,
        backend_id=backend_id,
        description="",
        icon=None,
        pics=[],
        config_json={},
        share_config={"access_level": "user", "user_uids": ["admin"]},
        is_default=False,
        is_subagent=is_subagent,
        can_manage=True,
    )


class _FakeAgentManager:
    def get_agent(self, backend_id: str):
        if backend_id in {"ChatbotAgent", "SubAgentBackend"}:
            return SimpleNamespace(context_schema=None)
        return None


class _ListRepo:
    items = [
        _agent("chatbot", backend_id="ChatbotAgent"),
        _agent("worker", backend_id="SubAgentBackend", is_subagent=True),
    ]
    include_subagents_calls: list[bool] = []

    def __init__(self, _db):
        pass

    async def ensure_default_agent(self):
        return self.items[0]

    async def list_visible(self, *, user, include_subagents: bool = False):
        del user
        self.include_subagents_calls.append(include_subagents)
        if include_subagents:
            return self.items
        return [item for item in self.items if not item.is_subagent]

    async def serialize(self, item, **_kwargs):
        return dict(item.__dict__)


class _CreateRepo(_ListRepo):
    created_payload = None

    async def create(self, **kwargs):
        type(self).created_payload = kwargs
        return _agent(kwargs["slug"], backend_id=kwargs["backend_id"], is_subagent=kwargs["is_subagent"])


class _RejectingCreateRepo(_ListRepo):
    async def create(self, **_kwargs):
        raise ValueError("SubAgentBackend 与 is_subagent 必须保持一致")


def _build_app(monkeypatch, repo_cls, *, role: str = "admin") -> TestClient:
    monkeypatch.setattr(agent_router_module, "agent_manager", _FakeAgentManager())
    monkeypatch.setattr(agent_router_module, "AgentRepository", repo_cls)

    app = FastAPI()
    app.include_router(agent_router_module.agent_router, prefix="/api")

    async def fake_db():
        return None

    async def fake_user():
        return _user(role)

    app.dependency_overrides[get_db] = fake_db
    app.dependency_overrides[get_required_user] = fake_user
    app.dependency_overrides[get_admin_user] = fake_user
    return TestClient(app)


def test_agent_list_excludes_subagents_by_default(monkeypatch):
    _ListRepo.include_subagents_calls = []
    client = _build_app(monkeypatch, _ListRepo)

    response = client.get("/api/agent")

    assert response.status_code == 200, response.text
    payload = response.json()
    assert [agent["slug"] for agent in payload["agents"]] == ["chatbot"]
    assert _ListRepo.include_subagents_calls == [False]


def test_agent_management_list_can_include_subagents(monkeypatch):
    _ListRepo.include_subagents_calls = []
    client = _build_app(monkeypatch, _ListRepo)

    response = client.get("/api/agent?include_subagents=true")

    assert response.status_code == 200, response.text
    payload = response.json()
    assert [agent["slug"] for agent in payload["agents"]] == ["chatbot", "worker"]
    assert payload["agents"][1]["is_subagent"] is True
    assert _ListRepo.include_subagents_calls == [True]


def test_normal_user_can_create_agent(monkeypatch):
    _CreateRepo.created_payload = None
    client = _build_app(monkeypatch, _CreateRepo, role="user")

    response = client.post(
        "/api/agent",
        json={
            "name": "Personal Bot",
            "slug": "personal-bot",
            "backend_id": "ChatbotAgent",
            "share_config": {"access_level": "global", "department_ids": [], "user_uids": []},
        },
    )

    assert response.status_code == 200, response.text
    assert _CreateRepo.created_payload["creator"].uid == "user"
    assert _CreateRepo.created_payload["creator"].role == "user"
    assert _CreateRepo.created_payload["share_config"] == {
        "access_level": "global",
        "department_ids": [],
        "user_uids": [],
    }


def test_create_subagent_backend_agent_sets_subagent_flag(monkeypatch):
    _CreateRepo.created_payload = None
    client = _build_app(monkeypatch, _CreateRepo)

    response = client.post(
        "/api/agent",
        json={
            "name": "Worker",
            "slug": "worker",
            "backend_id": "SubAgentBackend",
            "is_subagent": True,
        },
    )

    assert response.status_code == 200, response.text
    assert _CreateRepo.created_payload["backend_id"] == "SubAgentBackend"
    assert _CreateRepo.created_payload["is_subagent"] is True
    assert response.json()["agent"]["is_subagent"] is True


def test_create_subagent_backend_rejects_mismatched_flag(monkeypatch):
    client = _build_app(monkeypatch, _RejectingCreateRepo)

    response = client.post(
        "/api/agent",
        json={
            "name": "Worker",
            "slug": "worker",
            "backend_id": "SubAgentBackend",
            "is_subagent": False,
        },
    )

    assert response.status_code == 422
    assert "is_subagent" in response.json()["detail"]
