from __future__ import annotations

from fastapi.testclient import TestClient

from beaver.interfaces.channels.connections import ChannelConnectionStore
from beaver.interfaces.web.app import create_app
from beaver.services.agent_service import AgentService


def _app(tmp_path, monkeypatch):
    monkeypatch.setenv("BEAVER_BRIDGE_TOKEN", "bridge-token")
    config_path = tmp_path / "config.json"
    config_path.write_text(
        '{"agents": {"defaults": {"workspace": "%s"}}, "providers": {}}' % str(tmp_path),
        encoding="utf-8",
    )
    service = AgentService(config_path=config_path)
    app = create_app(service=service, manage_service_lifecycle=False)
    return app, service


def _connected_connection(tmp_path):
    state_dir = tmp_path / "state" / "channel_connections"
    store = ChannelConnectionStore(state_dir / "connections.json")
    connection = store.create(
        kind="weixin",
        mode="sidecar",
        display_name="Weixin Main",
        account_id="weixin:me",
        owner_user_id=None,
        auth_type="connector_session",
    )
    store.update_status(connection.connection_id, status="connected", last_error=None)
    return connection


def _connection_with_status(tmp_path, status: str):
    state_dir = tmp_path / "state" / "channel_connections"
    store = ChannelConnectionStore(state_dir / "connections.json")
    connection = store.create(
        kind="feishu",
        mode="sidecar",
        display_name="Feishu Main",
        account_id="feishu:app-1",
        owner_user_id=None,
        auth_type="connector_session",
    )
    store.update_status(connection.connection_id, status=status, last_error=None)
    return connection


def _payload(connection, *, event_id: str = "evt-1", delivery_attempt: int = 1) -> dict:
    return {
        "eventId": event_id,
        "timestamp": "2026-06-02T09:30:00Z",
        "deliveryAttempt": delivery_attempt,
        "connectionId": connection.connection_id,
        "channelId": connection.channel_id,
        "kind": "weixin",
        "accountId": "weixin:me",
        "peerId": "peer-1",
        "peerType": "dm",
        "userId": "sender-1",
        "threadId": None,
        "messageId": "msg-1",
        "messageType": "text",
        "content": "hello",
        "metadata": {},
    }


def test_bridge_endpoint_accepts_valid_event(tmp_path, monkeypatch) -> None:
    app, service = _app(tmp_path, monkeypatch)
    try:
        with TestClient(app) as client:
            connection = _connected_connection(tmp_path)
            response = client.post(
                "/api/channel-connector-bridge/events",
                headers={"Authorization": "Bearer bridge-token"},
                json=_payload(connection),
            )
        assert response.status_code == 200
        assert response.json()["accepted"] is True
    finally:
        service.close()


def test_bridge_endpoint_rejects_invalid_token(tmp_path, monkeypatch) -> None:
    app, service = _app(tmp_path, monkeypatch)
    try:
        with TestClient(app) as client:
            connection = _connected_connection(tmp_path)
            response = client.post(
                "/api/channel-connector-bridge/events",
                headers={"Authorization": "Bearer wrong"},
                json=_payload(connection),
            )
        assert response.status_code == 401
    finally:
        service.close()


def test_bridge_endpoint_rejects_connection_identity_mismatch(tmp_path, monkeypatch) -> None:
    app, service = _app(tmp_path, monkeypatch)
    try:
        with TestClient(app) as client:
            connection = _connected_connection(tmp_path)
            payload = _payload(connection)
            payload["channelId"] = "forged-channel"
            payload["kind"] = "feishu"
            payload["accountId"] = "feishu:attacker"
            response = client.post(
                "/api/channel-connector-bridge/events",
                headers={"Authorization": "Bearer bridge-token"},
                json=payload,
            )
        assert response.status_code == 403
        assert "does not match connection" in response.json()["detail"]
    finally:
        service.close()


def test_bridge_endpoint_rejects_inactive_connection(tmp_path, monkeypatch) -> None:
    app, service = _app(tmp_path, monkeypatch)
    try:
        with TestClient(app) as client:
            connection = _connection_with_status(tmp_path, "pairing")
            response = client.post(
                "/api/channel-connector-bridge/events",
                headers={"Authorization": "Bearer bridge-token"},
                json={
                    **_payload(connection),
                    "kind": "feishu",
                    "accountId": "feishu:app-1",
                },
            )
        assert response.status_code == 409
        assert "not connected" in response.json()["detail"]
    finally:
        service.close()


def test_bridge_endpoint_rejects_empty_or_oversized_content(tmp_path, monkeypatch) -> None:
    app, service = _app(tmp_path, monkeypatch)
    try:
        with TestClient(app) as client:
            connection = _connection_with_status(tmp_path, "connected")
            blank = client.post(
                "/api/channel-connector-bridge/events",
                headers={"Authorization": "Bearer bridge-token"},
                json={
                    **_payload(connection, event_id="blank"),
                    "kind": "feishu",
                    "accountId": "feishu:app-1",
                    "content": "   ",
                },
            )
            too_long = client.post(
                "/api/channel-connector-bridge/events",
                headers={"Authorization": "Bearer bridge-token"},
                json={
                    **_payload(connection, event_id="too-long"),
                    "kind": "feishu",
                    "accountId": "feishu:app-1",
                    "content": "x" * 20001,
                },
            )
        assert blank.status_code == 400
        assert too_long.status_code == 413
    finally:
        service.close()


def test_bridge_endpoint_dedupes_repeated_event(tmp_path, monkeypatch) -> None:
    app, service = _app(tmp_path, monkeypatch)
    try:
        with TestClient(app) as client:
            connection = _connected_connection(tmp_path)
            first = client.post(
                "/api/channel-connector-bridge/events",
                headers={"Authorization": "Bearer bridge-token"},
                json=_payload(connection),
            )
            second = client.post(
                "/api/channel-connector-bridge/events",
                headers={"Authorization": "Bearer bridge-token"},
                json=_payload(connection, delivery_attempt=2),
            )
        assert first.status_code == 200
        assert second.status_code in {200, 409}
        assert second.json()["duplicate"] is True
    finally:
        service.close()
