"""Template, contacts, OTP, webhook, monitoring tests."""
from __future__ import annotations

import pytest
from httpx import AsyncClient

from app.tests.conftest import TENANT_A, tenant_headers


async def _provider(client, headers):
    await client.post(
        "/api/v1/providers",
        headers=headers,
        json={
            "name": "Mock",
            "provider_kind": "mock",
            "channel": "sms",
            "priority": 1,
            "credentials": {},
        },
    )


@pytest.mark.asyncio
async def test_template_engine_flow(client: AsyncClient):
    h = tenant_headers(TENANT_A)
    created = await client.post(
        "/api/v1/templates",
        headers=h,
        json={
            "template_key": "welcome",
            "name": "Welcome",
            "channel": "sms",
            "locale": "fa",
            "body": "سلام {{name}}",
            "variables": ["name"],
        },
    )
    assert created.status_code == 201
    tid = created.json()["id"]
    assert created.json()["status"] == "draft"

    preview = await client.post(
        f"/api/v1/templates/{tid}/preview",
        headers=h,
        json={"variables": {"name": "Ali"}},
    )
    assert preview.status_code == 200
    assert preview.json()["rendered"] == "سلام Ali"

    await client.post(f"/api/v1/templates/{tid}/submit", headers=h)
    approved = await client.post(f"/api/v1/templates/{tid}/approve", headers=h)
    assert approved.status_code == 200
    assert approved.json()["status"] == "approved"

    await _provider(client, h)
    send = await client.post(
        "/api/v1/messages/send",
        headers=h,
        json={
            "channel": "sms",
            "to_address": "+989123333333",
            "template_key": "welcome",
            "template_variables": {"name": "Sara"},
            "process_immediately": True,
        },
    )
    assert send.status_code == 201
    assert "Sara" in send.json()[0]["body"]


@pytest.mark.asyncio
async def test_dynamic_contact_sources(client: AsyncClient):
    h = tenant_headers(TENANT_A)
    manual = await client.post(
        "/api/v1/contacts/manual",
        headers=h,
        json={"display_name": "User", "phone": "+989124444444"},
    )
    assert manual.status_code == 201

    csv_import = await client.post(
        "/api/v1/contacts/manual/import-csv",
        headers=h,
        json={"csv_text": "display_name,phone\nCSV User,+989125555555\n"},
    )
    assert csv_import.status_code == 201
    assert len(csv_import.json()) == 1

    source = await client.post(
        "/api/v1/contacts/sources",
        headers=h,
        json={
            "name": "CRM API",
            "source_type": "crm",
            "base_url": "http://crm.local",
            "endpoint_path": "/contacts",
            "auth_config": {
                "mock_contacts": [
                    {"id": "c1", "phone": "+989126666666", "display_name": "CRM Contact"}
                ]
            },
            "field_mapping": {
                "phone": "phone",
                "display_name": "display_name",
                "id": "id",
            },
        },
    )
    assert source.status_code == 201
    sid = source.json()["id"]

    resolved = await client.post(
        "/api/v1/contacts/resolve",
        headers=h,
        json={"source_id": sid, "channel": "sms"},
    )
    assert resolved.status_code == 200
    assert resolved.json()[0]["address"] == "+989126666666"
    assert resolved.json()[0]["source_type"] == "crm"
    # Ensure we did not create duplicated CRM rows in manual contacts
    manuals = await client.get("/api/v1/contacts/manual", headers=h)
    phones = {c["phone"] for c in manuals.json()}
    assert "+989126666666" not in phones


@pytest.mark.asyncio
async def test_otp_platform(client: AsyncClient):
    h = tenant_headers(TENANT_A)
    await _provider(client, h)
    req = await client.post(
        "/api/v1/otp/request",
        headers=h,
        json={"destination": "+989127777777", "channel": "sms", "purpose": "login"},
    )
    assert req.status_code == 201
    body = req.json()
    assert body["debug_code"]
    challenge_id = body["challenge_id"]

    bad = await client.post(
        "/api/v1/otp/verify",
        headers=h,
        json={
            "destination": "+989127777777",
            "code": "000000",
            "challenge_id": challenge_id,
        },
    )
    assert bad.status_code == 400

    ok = await client.post(
        "/api/v1/otp/verify",
        headers=h,
        json={
            "destination": "+989127777777",
            "code": body["debug_code"],
            "challenge_id": challenge_id,
        },
    )
    assert ok.status_code == 200
    assert ok.json()["verified"] is True


@pytest.mark.asyncio
async def test_webhook_delivery_update(client: AsyncClient):
    h = tenant_headers(TENANT_A)
    await _provider(client, h)
    send = await client.post(
        "/api/v1/messages/send",
        headers=h,
        json={
            "channel": "sms",
            "to_address": "+989128888888",
            "body": "track me",
            "process_immediately": True,
        },
    )
    mid = send.json()[0]["id"]
    hook = await client.post(
        "/api/v1/webhooks/incoming",
        headers=h,
        json={
            "provider_kind": "mock",
            "event_type": "delivered",
            "message_id": mid,
            "payload": {"status": "delivered"},
        },
    )
    assert hook.status_code == 201
    assert hook.json()["processed"] is True

    msg = await client.get(f"/api/v1/messages/{mid}", headers=h)
    assert msg.json()["status"] == "delivered"


@pytest.mark.asyncio
async def test_monitoring_stats(client: AsyncClient):
    h = tenant_headers(TENANT_A)
    await _provider(client, h)
    stats = await client.get("/api/v1/monitoring/stats", headers=h)
    assert stats.status_code == 200
    body = stats.json()
    assert "messages_by_status" in body
    assert "queue_by_status" in body
    assert "providers" in body
