"""Commercial Runtime Backend — registry, discovery, engines, resolvers."""
from __future__ import annotations

import uuid

import pytest


@pytest.mark.asyncio
async def test_commercial_health(client):
    resp = await client.get("/api/v1/commercial/health")
    assert resp.status_code == 200
    body = resp.json()
    assert body["status"] == "ok"
    assert body["domain"] == "commercial-runtime"


@pytest.mark.asyncio
async def test_discovery_catalog_lists_builtin_kinds(client):
    resp = await client.get("/api/v1/commercial/catalog")
    assert resp.status_code == 200
    body = resp.json()
    assert body["contract_version"] == "commercial.v1.2"
    kinds = {r["kind"] for r in body["registries"]}
    assert "products" in kinds
    assert "bundles" in kinds
    assert "capabilities" in kinds
    assert "notifications" in kinds
    assert "business_types" in kinds
    # FE must discover via href — every entry has href
    for r in body["registries"]:
        assert r["href"].startswith("/api/v1/commercial/")
        assert r["generic_href"].startswith("/api/v1/commercial/registries/")


@pytest.mark.asyncio
async def test_registry_crud_lifecycle_and_search(client):
    create = await client.post(
        "/api/v1/commercial/products",
        json={
            "product_code": "marketplace",
            "display_name": "Torbat Marketplace",
            "description": "Future product via registry only",
            "default_route": "/marketplace",
            "status": "draft",
            "visibility": "public",
            "category": "platform",
        },
    )
    assert create.status_code == 201, create.text
    obj = create.json()
    oid = obj["registry_object_id"]
    assert obj["product_code"] == "marketplace"
    assert obj["status"] == "draft"
    assert obj["version"]

    # draft not in public published list
    listed = await client.get("/api/v1/commercial/products", params={"status": "published"})
    assert listed.status_code == 200
    assert all(i["product_code"] != "marketplace" for i in listed.json()["products"])

    pub = await client.post(f"/api/v1/commercial/products/{oid}/publish")
    assert pub.status_code == 200
    assert pub.json()["status"] == "published"

    listed2 = await client.get("/api/v1/commercial/products", params={"q": "Marketplace"})
    assert listed2.status_code == 200
    codes = [i["product_code"] for i in listed2.json()["items"]]
    assert "marketplace" in codes

    patched = await client.patch(
        f"/api/v1/commercial/products/{oid}",
        json={"display_name": "Torbat Marketplace Pro", "trial_eligible": True},
    )
    assert patched.status_code == 200
    assert patched.json()["display_name"] == "Torbat Marketplace Pro"
    assert patched.json()["trial_eligible"] is True

    cloned = await client.post(f"/api/v1/commercial/products/{oid}/clone")
    assert cloned.status_code == 200
    assert cloned.json()["status"] == "draft"
    assert cloned.json()["clone_of_id"] == oid

    archived = await client.post(f"/api/v1/commercial/products/{oid}/archive")
    assert archived.status_code == 200
    assert archived.json()["status"] == "archived"

    deleted = await client.delete(f"/api/v1/commercial/products/{oid}")
    assert deleted.status_code == 200
    assert deleted.json()["is_deleted"] is True

    restored = await client.post(f"/api/v1/commercial/products/{oid}/restore")
    assert restored.status_code == 200
    assert restored.json()["status"] == "draft"
    assert restored.json()["is_deleted"] is False


@pytest.mark.asyncio
async def test_unlimited_future_kind_via_admin(client):
    kind = await client.post(
        "/api/v1/commercial/admin/kinds",
        json={
            "kind": "qr_products",
            "path": "qr-products",
            "display_name": "QR Products",
            "code_field": "qr_product_code",
            "list_envelope": "items",
        },
    )
    assert kind.status_code == 201, kind.text
    assert kind.json()["kind"] == "qr_products"

    catalog = await client.get("/api/v1/commercial/catalog")
    kinds = {r["kind"] for r in catalog.json()["registries"]}
    assert "qr_products" in kinds

    created = await client.post(
        "/api/v1/commercial/registries/qr_products",
        json={
            "qr_product_code": "qr.menu.v1",
            "display_name": "QR Menu",
            "status": "published",
        },
    )
    assert created.status_code == 201, created.text
    listed = await client.get("/api/v1/commercial/registries/qr_products")
    assert listed.status_code == 200
    assert any(i["qr_product_code"] == "qr.menu.v1" for i in listed.json()["items"])


@pytest.mark.asyncio
async def test_bundle_plan_license_resolvers(client):
    await client.post(
        "/api/v1/commercial/products",
        json={
            "product_code": "hospitality",
            "display_name": "Torbat Food",
            "status": "published",
            "default_route": "/hospitality",
        },
    )
    await client.post(
        "/api/v1/commercial/capabilities",
        json={
            "capability_code": "hospitality.digital_menu",
            "display_name": "Digital Menu",
            "status": "published",
            "service_key": "hospitality",
        },
    )
    await client.post(
        "/api/v1/commercial/pricing",
        json={
            "pricing_item_code": "price.restaurant.starter.monthly",
            "display_name": "Restaurant Starter Monthly",
            "status": "published",
            "currency": "IRR",
            "interval": "monthly",
            "trial_eligible": True,
            "trial_days": 14,
            "bundle_code": "bundle.restaurant.starter",
        },
    )
    await client.post(
        "/api/v1/commercial/plans",
        json={
            "plan_code": "plan.restaurant.starter.monthly",
            "display_name": "Restaurant Starter",
            "status": "published",
            "pricing_item_code": "price.restaurant.starter.monthly",
            "bundle_code": "bundle.restaurant.starter",
            "trial_eligible": True,
            "trial_days": 14,
            "limits": {"sites": {"limit": 1, "used": 0}},
        },
    )
    await client.post(
        "/api/v1/commercial/bundles",
        json={
            "bundle_code": "bundle.restaurant.starter",
            "display_name": "Restaurant Starter",
            "status": "published",
            "business_types": ["restaurant"],
            "product_codes": ["hospitality"],
            "capability_codes": ["hospitality.digital_menu"],
            "pricing_refs": [{"pricing_item_code": "price.restaurant.starter.monthly"}],
        },
    )

    resolved = await client.get("/api/v1/commercial/bundles/bundle.restaurant.starter/resolve")
    assert resolved.status_code == 200, resolved.text
    body = resolved.json()
    assert body["bundle_code"] == "bundle.restaurant.starter"
    assert any(p["product_code"] == "hospitality" for p in body["products"])
    assert any(c["capability_code"] == "hospitality.digital_menu" for c in body["capabilities"])

    plan = await client.get("/api/v1/commercial/plans/plan.restaurant.starter.monthly/resolve")
    assert plan.status_code == 200
    assert plan.json()["trial"]["days"] == 14
    assert plan.json()["renewal"]["interval"] == "monthly" or plan.json()["price"]

    tenant_id = str(uuid.uuid4())
    activated = await client.post(
        "/api/v1/commercial/subscriptions",
        json={
            "tenant_id": tenant_id,
            "bundle_code": "bundle.restaurant.starter",
            "plan_code": "plan.restaurant.starter.monthly",
            "status": "trialing",
        },
    )
    assert activated.status_code == 200, activated.text
    assert activated.json()["subscription"]["status"] == "trialing"
    assert "hospitality.digital_menu" in activated.json()["license"]["capability_codes"]

    ent = await client.post(
        "/api/v1/commercial/entitlements/check",
        json={"tenant_id": tenant_id, "feature_key": "hospitality.digital_menu"},
    )
    assert ent.status_code == 200
    assert ent.json()["has_access"] is True

    denied = await client.post(
        "/api/v1/commercial/entitlements/check",
        json={"tenant_id": tenant_id, "feature_key": "marketplace.dispatch"},
    )
    assert denied.status_code == 200
    assert denied.json()["has_access"] is False

    licenses = await client.get("/api/v1/commercial/licenses", params={"tenant_id": tenant_id})
    assert licenses.status_code == 200
    assert len(licenses.json()["items"]) >= 1


@pytest.mark.asyncio
async def test_recommendation_and_assessment_engines(client):
    await client.post(
        "/api/v1/commercial/recommendation-rules",
        json={
            "rule_id": "r.restaurant.base",
            "display_name": "Restaurant base",
            "status": "published",
            "priority": 100,
            "active": True,
            "match": {"business_type_code": "restaurant"},
            "emit": {
                "bundle_code": "bundle.restaurant.starter",
                "score": 100,
                "reason": "نوع رستوران",
                "products": ["hospitality", "payment"],
                "plans": ["plan.restaurant.starter.monthly"],
                "automation_packs": ["auto.hospitality.starter"],
            },
        },
    )
    await client.post(
        "/api/v1/commercial/assessment-schemas",
        json={
            "schema_code": "default.business.assessment",
            "display_name": "ارزیابی کسب‌وکار",
            "status": "published",
            "questions": [
                {
                    "question_id": "business_type_code",
                    "type": "select",
                    "label": "نوع کسب‌وکار",
                    "required": True,
                    "options_source": "business_types",
                }
            ],
        },
    )

    schema = await client.get("/api/v1/commercial/assessment/schema")
    assert schema.status_code == 200
    assert schema.json()["source"] == "registry"
    assert schema.json()["questions"]

    reco = await client.post(
        "/api/v1/commercial/recommendations",
        json={"business_type_code": "restaurant", "company_size": "small"},
    )
    assert reco.status_code == 200, reco.text
    body = reco.json()
    assert any(b["code"] == "bundle.restaurant.starter" for b in body["recommended_bundles"])
    assert any(p["code"] == "hospitality" for p in body["recommended_products"])
    assert any(p["code"] == "plan.restaurant.starter.monthly" for p in body["recommended_plans"])
    assert body["rule_trace"]
    assert "r.restaurant.base" in body["rule_trace"][0]


@pytest.mark.asyncio
async def test_openapi_includes_commercial_paths(client):
    resp = await client.get("/openapi.json")
    assert resp.status_code == 200
    paths = resp.json()["paths"]
    assert "/api/v1/commercial/catalog" in paths
    assert "/api/v1/commercial/products" in paths
    assert "/api/v1/commercial/recommendations" in paths
    assert "/api/v1/commercial/bundles/{bundle_code}/resolve" in paths
    assert "/api/v1/commercial/registries/{kind}" in paths
    assert "/api/v1/commercial/admin/kinds" in paths


@pytest.mark.asyncio
async def test_notifications_registry(client):
    created = await client.post(
        "/api/v1/commercial/notifications",
        json={
            "notification_code": "notify.welcome.email",
            "display_name": "Welcome email",
            "status": "published",
            "channel": "email",
            "subject": "خوش آمدید",
            "body_template": "سلام {{name}}",
        },
    )
    assert created.status_code == 201
    listed = await client.get("/api/v1/commercial/notifications")
    assert listed.status_code == 200
    assert any(i["notification_code"] == "notify.welcome.email" for i in listed.json()["items"])


@pytest.mark.asyncio
async def test_policy_evaluate(client):
    await client.post(
        "/api/v1/commercial/policies",
        json={
            "policy_code": "domain.custom",
            "display_name": "Domain",
            "status": "published",
            "custom_domain_allowed": True,
            "subdomain_only": False,
            "target": "domain",
            "reason": "allowed",
        },
    )
    resp = await client.post(
        "/api/v1/commercial/policies/evaluate",
        json={"policy_code": "domain.custom", "target": "domain"},
    )
    assert resp.status_code == 200
    assert resp.json()["custom_domain_allowed"] is True
