from __future__ import annotations

import base64

from fastapi.testclient import TestClient

from external_connector.app import create_app
from external_connector.providers.fake import FakeProvider
from external_connector.state import SidecarStateStore


def test_fake_provider_lists_weixin_and_feishu(tmp_path) -> None:
    provider = FakeProvider(SidecarStateStore(tmp_path / "state.json"))

    connectors = provider.connectors()

    assert [item["kind"] for item in connectors] == ["weixin", "feishu"]
    assert connectors[0]["authType"] == "qr"


def test_fake_provider_session_flow(tmp_path) -> None:
    provider = FakeProvider(SidecarStateStore(tmp_path / "state.json"))

    session = provider.start_session(
        {
            "kind": "weixin",
            "connectionId": "conn_1",
            "channelId": "weixin-main",
            "displayName": "Weixin Main",
            "callbackBaseUrl": "http://beaver:8080",
            "options": {},
        }
    )
    loaded = provider.get_session(session["sessionId"])

    assert session["status"] == "qr_ready"
    prefix = "data:image/svg+xml;base64,"
    assert session["qrImage"].startswith(prefix)
    svg = base64.b64decode(session["qrImage"][len(prefix) :]).decode("utf-8")
    assert svg.startswith("<svg")
    assert "FAKE QR" in svg
    assert loaded["sessionId"] == session["sessionId"]


def test_fake_provider_send_returns_idempotent_result(tmp_path) -> None:
    provider = FakeProvider(SidecarStateStore(tmp_path / "state.json"))
    payload = {
        "requestId": "out_1",
        "connectionId": "conn_1",
        "channelId": "weixin-main",
        "kind": "weixin",
        "target": {"peerId": "peer-1", "peerType": "dm", "threadId": None},
        "content": "hello",
        "metadata": {},
    }

    first = provider.send(payload)
    second = provider.send(payload)

    assert first == second
    assert first["ok"] is True


def test_sidecar_http_api_requires_bearer_token(tmp_path) -> None:
    app = create_app(provider=FakeProvider(SidecarStateStore(tmp_path / "state.json")), api_token="sidecar-token")

    with TestClient(app) as client:
        response = client.get("/connectors")

    assert response.status_code == 401


def test_sidecar_http_api_fails_closed_without_configured_token(tmp_path) -> None:
    app = create_app(provider=FakeProvider(SidecarStateStore(tmp_path / "state.json")), api_token="")

    with TestClient(app) as client:
        response = client.get("/connectors")
        health = client.get("/health")

    assert response.status_code == 503
    assert health.status_code == 200


def test_sidecar_http_api_session_and_send(tmp_path) -> None:
    app = create_app(provider=FakeProvider(SidecarStateStore(tmp_path / "state.json")), api_token="sidecar-token")
    headers = {"Authorization": "Bearer sidecar-token"}

    with TestClient(app) as client:
        connectors = client.get("/connectors", headers=headers)
        session = client.post(
            "/connector-sessions",
            headers=headers,
            json={
                "kind": "weixin",
                "connectionId": "conn_1",
                "channelId": "weixin-main",
                "displayName": "Weixin Main",
                "callbackBaseUrl": "http://beaver:8080",
                "options": {},
            },
        )
        session_id = session.json()["sessionId"]
        loaded = client.get(f"/connector-sessions/{session_id}", headers=headers)
        sent = client.post(
            "/send",
            headers=headers,
            json={
                "requestId": "out_1",
                "connectionId": "conn_1",
                "channelId": "weixin-main",
                "kind": "weixin",
                "target": {"peerId": "peer-1", "peerType": "dm", "threadId": None},
                "content": "hello",
                "metadata": {},
            },
        )

    assert connectors.status_code == 200
    assert session.status_code == 200
    assert loaded.json()["sessionId"] == session_id
    assert sent.json()["ok"] is True


def test_sidecar_http_api_returns_conflict_for_processing_send(tmp_path) -> None:
    store = SidecarStateStore(tmp_path / "state.json", send_processing_ttl_seconds=60)
    store.begin_send(connection_id="conn_1", request_id="out_1")
    app = create_app(provider=FakeProvider(store), api_token="sidecar-token")
    headers = {"Authorization": "Bearer sidecar-token"}

    with TestClient(app) as client:
        response = client.post(
            "/send",
            headers=headers,
            json={
                "requestId": "out_1",
                "connectionId": "conn_1",
                "channelId": "weixin-main",
                "kind": "weixin",
                "target": {"peerId": "peer-1", "peerType": "dm", "threadId": None},
                "content": "hello",
                "metadata": {},
            },
        )

    assert response.status_code == 409
    assert response.json()["retryAfterSeconds"] == 5
