"""Phase 12.1 Digital Menu Catalog 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,
            "is_vegetarian": True,
            "preparation_minutes": 5,
            "tags": ["coffee", "hot"],
        },
        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_digital_menu_catalog_happy_path(client):
    seed = await _seed_menu_item(client, TENANT_A)
    h = seed["headers"]
    venue_id = seed["venue_id"]
    item_id = seed["item_id"]
    menu_id = seed["menu_id"]

    assert seed["item"]["is_vegetarian"] is True
    assert seed["item"]["preparation_minutes"] == 5
    assert seed["item"]["tags"] == ["coffee", "hot"]

    allergen = await client.post(
        "/api/v1/allergens",
        json={"venue_id": venue_id, "code": "milk", "name": "Milk"},
        headers=h,
    )
    assert allergen.status_code == 201, allergen.text
    allergen_id = allergen.json()["id"]

    group = await client.post(
        "/api/v1/modifier-groups",
        json={
            "venue_id": venue_id,
            "code": "size",
            "name": "Size",
            "selection_mode": "single",
            "min_select": 1,
            "max_select": 1,
            "is_required": True,
        },
        headers=h,
    )
    assert group.status_code == 201, group.text
    group_id = group.json()["id"]
    assert group.json()["min_select"] == 1

    option = await client.post(
        "/api/v1/modifier-options",
        json={
            "venue_id": venue_id,
            "modifier_group_id": group_id,
            "code": "large",
            "name": "Large",
            "price_delta": 20000,
        },
        headers=h,
    )
    assert option.status_code == 201, option.text

    link_mod = await client.post(
        "/api/v1/menu-item-modifiers/link",
        json={
            "venue_id": venue_id,
            "menu_item_id": item_id,
            "modifier_group_id": group_id,
        },
        headers=h,
    )
    assert link_mod.status_code == 201, link_mod.text

    link_all = await client.post(
        "/api/v1/menu-item-allergens/link",
        json={
            "venue_id": venue_id,
            "menu_item_id": item_id,
            "allergen_id": allergen_id,
            "is_contains": True,
        },
        headers=h,
    )
    assert link_all.status_code == 201, link_all.text

    window = await client.post(
        "/api/v1/availability-windows",
        json={
            "venue_id": venue_id,
            "scope": "item",
            "target_id": item_id,
            "code": "lunch",
            "name": "Lunch",
            "weekday": 1,
            "start_time": "11:00",
            "end_time": "15:00",
        },
        headers=h,
    )
    assert window.status_code == 201, window.text

    media = await client.post(
        "/api/v1/menu-media-refs",
        json={
            "venue_id": venue_id,
            "menu_item_id": item_id,
            "kind": "image",
            "file_ref": "storage://hospitality/latte.jpg",
            "alt_text": "Latte",
        },
        headers=h,
    )
    assert media.status_code == 201, media.text

    loc = await client.post(
        "/api/v1/menu-localizations/upsert",
        json={
            "venue_id": venue_id,
            "target_type": "item",
            "target_id": item_id,
            "locale": "fa-IR",
            "name": "لاته",
            "description": "قهوه با شیر",
        },
        headers=h,
    )
    assert loc.status_code == 200, loc.text
    assert loc.json()["name"] == "لاته"

    listed = await client.get("/api/v1/allergens", 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.ALLERGEN_CREATED.value in published
    assert HospitalityEventType.MODIFIER_GROUP_CREATED.value in published
    assert HospitalityEventType.MENU_ITEM_MODIFIER_LINKED.value in published
    assert HospitalityEventType.AVAILABILITY_WINDOW_CREATED.value in published
    assert HospitalityEventType.MENU_MEDIA_REF_CREATED.value in published
    assert HospitalityEventType.MENU_LOCALIZATION_UPSERTED.value in published
    assert menu_id  # keep seed used


@pytest.mark.asyncio
async def test_catalog_tenant_isolation(client):
    seed = await _seed_menu_item(client, TENANT_A, venue_code="iso-a")
    allergen = await client.post(
        "/api/v1/allergens",
        json={"venue_id": seed["venue_id"], "code": "nuts", "name": "Nuts"},
        headers=seed["headers"],
    )
    assert allergen.status_code == 201
    allergen_id = allergen.json()["id"]

    denied = await client.get(
        f"/api/v1/allergens/{allergen_id}",
        headers=tenant_headers(TENANT_B),
    )
    assert denied.status_code == 404


@pytest.mark.asyncio
async def test_availability_window_validation(client):
    seed = await _seed_menu_item(client, TENANT_A, venue_code="val-a", item_code="tea")
    bad = await client.post(
        "/api/v1/availability-windows",
        json={
            "venue_id": seed["venue_id"],
            "scope": "item",
            "target_id": seed["item_id"],
            "code": "bad",
            "name": "Bad",
            "start_time": "18:00",
            "end_time": "10:00",
        },
        headers=seed["headers"],
    )
    assert bad.status_code == 422


@pytest.mark.asyncio
async def test_modifier_selection_bounds_validation(client):
    seed = await _seed_menu_item(client, TENANT_A, venue_code="mod-a", item_code="mocha")
    bad = await client.post(
        "/api/v1/modifier-groups",
        json={
            "venue_id": seed["venue_id"],
            "code": "extras",
            "name": "Extras",
            "selection_mode": "multiple",
            "min_select": 3,
            "max_select": 1,
        },
        headers=seed["headers"],
    )
    assert bad.status_code == 422


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