"""Phase 12.2 QR Menu & QR Ordering API / tenant / validation tests."""
from __future__ import annotations

import pytest

from app.events.publisher import get_event_publisher
from app.events.types import HospitalityEventType
from app.tests.conftest import TENANT_A, TENANT_B, tenant_headers


async def _seed_menu_item(client, tenant_id, *, venue_code: str = "v1", item_code: str = "latte"):
    h = tenant_headers(tenant_id)
    venue = await client.post(
        "/api/v1/venues",
        json={"code": venue_code, "name": "Cafe", "status": "active", "venue_format": "cafe"},
        headers=h,
    )
    assert venue.status_code == 201, venue.text
    venue_id = venue.json()["id"]

    menu = await client.post(
        "/api/v1/menus",
        json={"venue_id": venue_id, "code": "day", "name": "Day Menu"},
        headers=h,
    )
    assert menu.status_code == 201, menu.text
    menu_id = menu.json()["id"]

    category = await client.post(
        "/api/v1/menu-categories",
        json={
            "venue_id": venue_id,
            "menu_id": menu_id,
            "code": "drinks",
            "name": "Drinks",
        },
        headers=h,
    )
    assert category.status_code == 201, category.text

    item = await client.post(
        "/api/v1/menu-items",
        json={
            "venue_id": venue_id,
            "menu_id": menu_id,
            "category_id": category.json()["id"],
            "code": item_code,
            "name": "Latte",
            "base_price": 150000,
        },
        headers=h,
    )
    assert item.status_code == 201, item.text
    return {
        "headers": h,
        "venue_id": venue_id,
        "menu_id": menu_id,
        "item_id": item.json()["id"],
        "item": item.json(),
    }


@pytest.mark.asyncio
async def test_qr_menu_ordering_happy_path(client):
    seed = await _seed_menu_item(client, TENANT_A)
    h = seed["headers"]
    venue_id = seed["venue_id"]
    menu_id = seed["menu_id"]
    item_id = seed["item_id"]

    qr_code = await client.post(
        "/api/v1/qr-codes",
        json={
            "venue_id": venue_id,
            "code": "table-1",
            "name": "Table 1 QR",
            "target_type": "menu",
            "menu_id": menu_id,
            "ordering_enabled": True,
        },
        headers=h,
    )
    assert qr_code.status_code == 201, qr_code.text
    qr_code_id = qr_code.json()["id"]
    qr_token = qr_code.json()["token"]
    assert qr_token

    by_token = await client.get(f"/api/v1/qr-codes/by-token/{qr_token}", headers=h)
    assert by_token.status_code == 200, by_token.text
    assert by_token.json()["id"] == qr_code_id

    menu_session = await client.post(
        "/api/v1/qr-menu-sessions",
        json={"venue_id": venue_id, "qr_code_id": qr_code_id, "locale": "fa-IR"},
        headers=h,
    )
    assert menu_session.status_code == 201, menu_session.text
    menu_session_id = menu_session.json()["id"]
    menu_session_token = menu_session.json()["session_token"]

    by_token_ms = await client.get(
        f"/api/v1/qr-menu-sessions/by-token/{menu_session_token}", headers=h
    )
    assert by_token_ms.status_code == 200, by_token_ms.text

    ordering_session = await client.post(
        "/api/v1/qr-ordering-sessions",
        json={
            "venue_id": venue_id,
            "qr_code_id": qr_code_id,
            "qr_menu_session_id": menu_session_id,
        },
        headers=h,
    )
    assert ordering_session.status_code == 201, ordering_session.text
    ordering_session_id = ordering_session.json()["id"]
    assert ordering_session.json()["status"] == "draft"

    cart = await client.post(
        "/api/v1/carts",
        json={"venue_id": venue_id, "ordering_session_id": ordering_session_id},
        headers=h,
    )
    assert cart.status_code == 201, cart.text
    cart_id = cart.json()["id"]
    assert cart.json()["status"] == "active"

    line = await client.post(
        "/api/v1/cart-lines",
        json={
            "venue_id": venue_id,
            "cart_id": cart_id,
            "menu_item_id": item_id,
            "quantity": 2,
        },
        headers=h,
    )
    assert line.status_code == 201, line.text
    assert line.json()["quantity"] == 2
    assert line.json()["unit_price"] == 150000

    submitted = await client.post(
        f"/api/v1/qr-ordering-sessions/{ordering_session_id}/submit", headers=h
    )
    assert submitted.status_code == 200, submitted.text
    assert submitted.json()["status"] == "submitted"

    listed = await client.get("/api/v1/qr-codes", headers=h)
    assert listed.status_code == 200
    assert len(listed.json()) >= 1

    published = {e.event_type for e in get_event_publisher().published}
    assert HospitalityEventType.QR_CODE_CREATED.value in published
    assert HospitalityEventType.QR_MENU_SESSION_CREATED.value in published
    assert HospitalityEventType.QR_ORDERING_SESSION_CREATED.value in published
    assert HospitalityEventType.CART_CREATED.value in published
    assert HospitalityEventType.CART_LINE_ADDED.value in published
    assert HospitalityEventType.QR_ORDERING_SESSION_SUBMITTED.value in published


@pytest.mark.asyncio
async def test_qr_code_tenant_isolation(client):
    seed = await _seed_menu_item(client, TENANT_A, venue_code="iso-a")
    qr_code = await client.post(
        "/api/v1/qr-codes",
        json={
            "venue_id": seed["venue_id"],
            "code": "iso-qr",
            "name": "Iso QR",
            "target_type": "menu",
            "menu_id": seed["menu_id"],
        },
        headers=seed["headers"],
    )
    assert qr_code.status_code == 201
    qr_code_id = qr_code.json()["id"]

    denied = await client.get(
        f"/api/v1/qr-codes/{qr_code_id}",
        headers=tenant_headers(TENANT_B),
    )
    assert denied.status_code == 404


@pytest.mark.asyncio
async def test_qr_code_requires_menu_id_for_menu_target(client):
    seed = await _seed_menu_item(client, TENANT_A, venue_code="val-a", item_code="tea")
    bad = await client.post(
        "/api/v1/qr-codes",
        json={
            "venue_id": seed["venue_id"],
            "code": "bad-qr",
            "name": "Bad QR",
            "target_type": "menu",
        },
        headers=seed["headers"],
    )
    assert bad.status_code == 422


@pytest.mark.asyncio
async def test_qr_ordering_session_requires_ordering_enabled(client):
    seed = await _seed_menu_item(client, TENANT_A, venue_code="ord-a", item_code="mocha")
    qr_code = await client.post(
        "/api/v1/qr-codes",
        json={
            "venue_id": seed["venue_id"],
            "code": "no-order",
            "name": "No Order QR",
            "target_type": "menu",
            "menu_id": seed["menu_id"],
            "ordering_enabled": False,
        },
        headers=seed["headers"],
    )
    assert qr_code.status_code == 201, qr_code.text

    bad = await client.post(
        "/api/v1/qr-ordering-sessions",
        json={"venue_id": seed["venue_id"], "qr_code_id": qr_code.json()["id"]},
        headers=seed["headers"],
    )
    assert bad.status_code == 422


@pytest.mark.asyncio
async def test_cart_line_quantity_validation(client):
    seed = await _seed_menu_item(client, TENANT_A, venue_code="qty-a", item_code="cake")
    h = seed["headers"]
    qr_code = await client.post(
        "/api/v1/qr-codes",
        json={
            "venue_id": seed["venue_id"],
            "code": "qty-qr",
            "name": "Qty QR",
            "target_type": "menu",
            "menu_id": seed["menu_id"],
            "ordering_enabled": True,
        },
        headers=h,
    )
    assert qr_code.status_code == 201, qr_code.text

    ordering_session = await client.post(
        "/api/v1/qr-ordering-sessions",
        json={"venue_id": seed["venue_id"], "qr_code_id": qr_code.json()["id"]},
        headers=h,
    )
    assert ordering_session.status_code == 201, ordering_session.text

    cart = await client.post(
        "/api/v1/carts",
        json={
            "venue_id": seed["venue_id"],
            "ordering_session_id": ordering_session.json()["id"],
        },
        headers=h,
    )
    assert cart.status_code == 201, cart.text

    bad = await client.post(
        "/api/v1/cart-lines",
        json={
            "venue_id": seed["venue_id"],
            "cart_id": cart.json()["id"],
            "menu_item_id": seed["item_id"],
            "quantity": 0,
        },
        headers=h,
    )
    assert bad.status_code == 422


@pytest.mark.asyncio
async def test_qr_menu_ordering_still_enabled_in_phase_12_3(client):
    resp = await client.get("/capabilities")
    assert resp.status_code == 200
    body = resp.json()
    assert body["features"]["qr_menu"] is True
    assert body["features"]["qr_ordering"] is True
    assert body["features"]["ordering_engine"] is False
    assert body["features"]["pos_engine"] is False
