from fastapi.testclient import TestClient
import pytest

import services.sales_service.app as sales_module


def _headers(tenant_id: str = "tenant_test") -> dict[str, str]:
    return {"X-User": "admin", "X-Role": "admin", "X-Tenant-ID": tenant_id}


def _create_lead(client: TestClient) -> tuple[dict, str]:
    created = client.post(
        "/api/v1/leads",
        json={
            "source_type": "crm",
            "source_channel": "telegram",
            "full_name": "Test Buyer",
            "company_name": "Sales QA",
            "phone": "+77001234567",
            "email": "buyer@test.local",
            "lead_temperature": "hot",
            "lead_score": 82,
            "initial_need_summary": "Need a commercial offer and a callback.",
            "preferred_channel": "telegram",
            "assigned_agent_type": "text_ai",
            "status": "new_qualified_lead",
            "priority": 3,
            "title": "Lead: Test Buyer",
        },
        headers=_headers(),
    )
    assert created.status_code == 200
    lead = created.json()
    deals = client.get("/api/v1/deals", headers=_headers())
    assert deals.status_code == 200
    deal_id = next(item["deal_id"] for item in deals.json() if item["lead_id"] == lead["lead_id"])
    return lead, deal_id


class _DummySyncResponse:
    def __init__(self, payload: dict[str, str]):
        self._payload = payload
        self.status_code = 200
        self.text = ""

    def raise_for_status(self) -> None:
        return None

    def json(self) -> dict[str, str]:
        return self._payload


class _DummyHttpxClient:
    requests: list[dict] = []
    response_payload: dict[str, str] = {}

    def __init__(self, timeout: float):
        self.timeout = timeout

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc, tb):
        return None

    def post(self, url: str, json: dict | None = None, headers: dict | None = None):
        self.__class__.requests.append(
            {
                "url": url,
                "json": json or {},
                "headers": headers or {},
                "timeout": self.timeout,
            }
        )
        return _DummySyncResponse(self.__class__.response_payload)


def test_sales_lead_creation_auto_creates_deal_and_workspace():
    client = TestClient(sales_module.app)

    lead, deal_id = _create_lead(client)
    workspace = client.get(f"/api/v1/deals/{deal_id}/workspace", headers=_headers())

    assert workspace.status_code == 200
    payload = workspace.json()
    assert payload["lead"]["lead_id"] == lead["lead_id"]
    assert payload["deal"]["deal_id"] == deal_id
    assert payload["deal"]["preferred_channel"] == "telegram"
    assert payload["timeline"]


def test_sales_bind_telegram_and_send_outbound_message(monkeypatch):
    client = TestClient(sales_module.app)
    _, deal_id = _create_lead(client)
    _DummyHttpxClient.requests = []
    _DummyHttpxClient.response_payload = {"ok": True}
    monkeypatch.setattr(sales_module.httpx, "Client", _DummyHttpxClient)
    monkeypatch.setenv("SALES_TELEGRAM_BRIDGE_ENABLED", "1")

    created_communication = client.post(
        f"/api/v1/deals/{deal_id}/communications/text",
        json={
            "channel_type": "text",
            "direction": "outbound",
            "agent_type": "text_ai",
            "subject": "Telegram follow-up",
        },
        headers=_headers(),
    )
    assert created_communication.status_code == 200
    communication = created_communication.json()

    bound = client.post(
        f"/api/v1/communications/{communication['communication_id']}/bind-external",
        json={
            "channel_provider": "telegram",
            "telegram_thread_id": "tg-thread-42",
            "telegram_chat_id": "tg-chat-42",
        },
        headers=_headers(),
    )
    assert bound.status_code == 200
    assert bound.json()["metadata"]["telegram_thread_id"] == "tg-thread-42"

    outbound = client.post(
        "/api/v1/messages/outbound",
        json={
            "deal_id": deal_id,
            "communication_id": communication["communication_id"],
            "channel_provider": "telegram",
            "sender_type": "human",
            "sender_id": "admin",
            "body": "Please check the offer in Telegram.",
            "metadata": {"telegram_thread_id": "tg-thread-42"},
        },
        headers=_headers(),
    )
    assert outbound.status_code == 200
    assert outbound.json()["delivery_status"] == "sent"
    assert _DummyHttpxClient.requests
    assert _DummyHttpxClient.requests[0]["url"].endswith("/integrations/telegram/threads/tg-thread-42/messages")
    assert _DummyHttpxClient.requests[0]["json"]["text"] == "Please check the offer in Telegram."

    switched = client.post(
        f"/api/v1/communications/{communication['communication_id']}/switch-channel",
        json={
            "to_channel": "voice",
            "reason_for_channel_switch": "Need to clarify details by phone",
        },
        headers=_headers(),
    )
    assert switched.status_code == 200

    workspace = client.get(f"/api/v1/deals/{deal_id}/workspace", headers=_headers())
    assert workspace.status_code == 200
    payload = workspace.json()
    assert payload["deal"]["current_channel"] == "voice"
    assert payload["channel_switches"][0]["to_channel"] == "voice"


def test_sales_inbound_call_bridges_voice_runtime(monkeypatch):
    client = TestClient(sales_module.app)
    _, deal_id = _create_lead(client)
    _DummyHttpxClient.requests = []
    _DummyHttpxClient.response_payload = {"voice_session_id": "avs_sales_case_01"}
    monkeypatch.setattr(sales_module.httpx, "Client", _DummyHttpxClient)
    monkeypatch.setenv("SALES_VOICE_RUNTIME_ENABLED", "1")

    response = client.post(
        "/api/v1/calls/inbound-webhook",
        json={
            "deal_id": deal_id,
            "phone_number": "+77001234567",
            "provider": "asterisk",
            "external_call_id": "call-sales-01",
            "subject": "Inbound sales call",
        },
        headers=_headers(),
    )
    assert response.status_code == 200
    assert _DummyHttpxClient.requests
    assert _DummyHttpxClient.requests[0]["url"].endswith("/internal/voice-ai/sessions")
    assert _DummyHttpxClient.requests[0]["json"]["call_id"] == "call-sales-01"

    workspace = client.get(f"/api/v1/deals/{deal_id}/workspace", headers=_headers())
    assert workspace.status_code == 200
    communication = workspace.json()["communications"][0]
    assert communication["channel_type"] == "voice"
    assert communication["metadata"]["voice_session_id"] == "avs_sales_case_01"


def test_sales_internal_telegram_sync_auto_creates_workspace():
    client = TestClient(sales_module.app)

    response = client.post(
        "/internal/sales-sync/telegram",
        json={
            "thread_id": "tg-thread-auto-01",
            "chat_id": "tg-chat-auto-01",
            "interaction_id": "int_tg_auto_01",
            "phone_number": "+77005550101",
            "display_name": "Telegram Prospect",
            "queue_id": "q_sales",
            "status": "new",
            "ai_state": "queued",
            "message_id": "msg_tg_auto_01",
            "external_message_id": "ext_tg_auto_01",
            "text": "Здравствуйте, нужен расчет и коммерческое предложение.",
            "direction": "inbound",
            "author_type": "customer",
            "author_id": "tg-user-01",
            "metadata": {"username": "sales_prospect"},
        },
        headers=_headers(),
    )

    assert response.status_code == 200
    workspace = response.json()
    assert workspace["deal"]["current_channel"] == "telegram"
    assert workspace["deal"]["preferred_channel"] == "telegram"
    assert workspace["communications"][0]["channel_provider"] == "telegram"
    assert workspace["communications"][0]["metadata"]["telegram_thread_id"] == "tg-thread-auto-01"
    assert workspace["messages"][0]["external_message_id"] == "ext_tg_auto_01"


def test_sales_internal_telegram_sync_moves_pipeline_every_three_customer_messages():
    client = TestClient(sales_module.app)
    tenant_id = "tenant_tg_autostage"

    def post_message(index: int) -> dict:
        response = client.post(
            "/internal/sales-sync/telegram",
            json={
                "thread_id": "tg-thread-autostage-01",
                "chat_id": "tg-chat-autostage-01",
                "interaction_id": "int_tg_autostage_01",
                "display_name": "Autostage Prospect",
                "message_id": f"msg_tg_autostage_{index}",
                "external_message_id": f"ext_tg_autostage_{index}",
                "text": f"Сообщение клиента {index}",
                "direction": "inbound",
                "author_type": "customer",
                "author_id": "tg-user-autostage",
            },
            headers=_headers(tenant_id),
        )
        assert response.status_code == 200
        return response.json()

    stage_codes = [post_message(index)["stage"]["code"] for index in range(1, 7)]

    assert stage_codes[0] == "new_qualified_lead"
    assert stage_codes[1] == "new_qualified_lead"
    assert stage_codes[2] == "warm_lead"
    assert stage_codes[3] == "warm_lead"
    assert stage_codes[4] == "warm_lead"
    assert stage_codes[5] == "hot_lead"

    duplicate = post_message(6)
    assert duplicate["stage"]["code"] == "hot_lead"
    assert len(duplicate["messages"]) == 6


def test_sales_internal_voice_sync_creates_call_and_transcript():
    client = TestClient(sales_module.app)

    response = client.post(
        "/internal/sales-sync/voice",
        json={
            "call_id": "call-auto-voice-01",
            "interaction_id": "int_voice_auto_01",
            "queue_id": "q_voice_sales",
            "queue_code": "voice_sales",
            "caller_number": "+77005550202",
            "caller_name": "Voice Prospect",
            "voice_session_id": "avs_auto_01",
            "ai_session_id": "ais_auto_01",
            "ai_state": "completed",
            "telephony_status": "ended",
            "call_status": "completed",
            "started_at": "2026-05-08T10:00:00Z",
            "ended_at": "2026-05-08T10:03:00Z",
            "summary": "Клиент запросил прайс и условия подключения.",
            "transcript_text": "customer: Добрый день, нужен прайс.\nassistant: Подготовлю информацию.",
            "metadata": {"agent_profile": "voice_sales"},
        },
        headers=_headers(),
    )

    assert response.status_code == 200
    workspace = response.json()
    assert workspace["deal"]["current_channel"] == "voice"
    assert workspace["communications"][0]["channel_type"] == "voice"
    assert workspace["communications"][0]["metadata"]["voice_session_id"] == "avs_auto_01"
    assert workspace["calls"][0]["external_call_id"] == "call-auto-voice-01"
    assert workspace["transcripts"][0]["transcript_text"].startswith("customer:")


def test_sales_list_deals_query_matches_external_links():
    client = TestClient(sales_module.app)

    voice_workspace = client.post(
        "/internal/sales-sync/voice",
        json={
            "call_id": "call-search-voice-01",
            "interaction_id": "int_search_voice_01",
            "caller_number": "+77005550303",
            "caller_name": "Voice Search Prospect",
            "voice_session_id": "avs_search_01",
            "call_status": "completed",
        },
        headers=_headers(),
    )
    assert voice_workspace.status_code == 200

    telegram_workspace = client.post(
        "/internal/sales-sync/telegram",
        json={
            "thread_id": "tg-thread-search-01",
            "chat_id": "tg-chat-search-01",
            "interaction_id": "int_search_tg_01",
            "display_name": "Telegram Search Prospect",
            "text": "Need pricing details",
        },
        headers=_headers(),
    )
    assert telegram_workspace.status_code == 200

    by_voice_session = client.get("/api/v1/deals?query=avs_search_01", headers=_headers())
    assert by_voice_session.status_code == 200
    assert any(item["deal_id"] == voice_workspace.json()["deal"]["deal_id"] for item in by_voice_session.json())

    by_call_id = client.get("/api/v1/deals?query=call-search-voice-01", headers=_headers())
    assert by_call_id.status_code == 200
    assert any(item["deal_id"] == voice_workspace.json()["deal"]["deal_id"] for item in by_call_id.json())

    by_thread_id = client.get("/api/v1/deals?query=tg-thread-search-01", headers=_headers())
    assert by_thread_id.status_code == 200
    assert any(item["deal_id"] == telegram_workspace.json()["deal"]["deal_id"] for item in by_thread_id.json())
