"""Template system API tests — Phase 11.4."""
from __future__ import annotations

import pytest

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


async def _workspace(client, code="ws-tpl"):
    resp = await client.post(
        "/api/v1/workspaces",
        json={"code": code, "name": "Workspace", "status": "active"},
        headers=tenant_headers(TENANT_A),
    )
    assert resp.status_code == 201, resp.text
    return resp.json()


async def _site(client, workspace_id: str, code="main"):
    resp = await client.post(
        "/api/v1/sites",
        json={"workspace_id": workspace_id, "code": code, "name": "Main Site"},
        headers=tenant_headers(TENANT_A),
    )
    assert resp.status_code == 201, resp.text
    return resp.json()


@pytest.mark.asyncio
async def test_health_phase_114(client):
    """Prior phase capabilities remain intact after 11.5."""
    resp = await client.get("/health")
    assert resp.status_code == 200
    assert resp.json()["version"].startswith("0.11.")

    caps = await client.get("/capabilities")
    body = caps.json()
    assert body["features"]["templates"] is True
    assert body["features"]["template_versions"] is True
    assert body["features"]["template_instantiation"] is True
    assert body["features"]["forms"] is True
    assert body["features"]["surveys"] is True
    # Prior phase capabilities remain intact.
    assert body["features"]["themes"] is True
    assert body["features"]["layouts"] is True
    # Current phase advances version/phase markers.
    assert body["phase"] == "11.10"
    assert body["version"].startswith("0.11.10")

@pytest.mark.asyncio
async def test_template_full_lifecycle_and_instantiation(client):
    ws = await _workspace(client)
    workspace_id = ws["id"]
    site = await _site(client, workspace_id)

    # --- Create template (draft) ---
    template = await client.post(
        "/api/v1/templates",
        json={
            "workspace_id": workspace_id,
            "code": "landing-starter",
            "name": "Landing Starter",
            "page_type": "landing",
            "category": "starter",
            "is_starter_pack": True,
        },
        headers=tenant_headers(TENANT_A),
    )
    assert template.status_code == 201, template.text
    template_id = template.json()["id"]
    assert template.json()["status"] == "draft"
    assert template.json()["latest_version_number"] == 0

    # --- Create version (draft) ---
    version = await client.post(
        "/api/v1/template-versions",
        json={
            "workspace_id": workspace_id,
            "template_id": template_id,
            "blueprint_json": {
                "page_type": "landing",
                "summary": "Landing page from template",
                "content_shell": {"hero": True},
                "placement_shells": [{"slot": "hero", "component_code": "hero-1"}],
            },
            "changelog": "Initial version",
        },
        headers=tenant_headers(TENANT_A),
    )
    assert version.status_code == 201, version.text
    version_id = version.json()["id"]
    assert version.json()["version_number"] == 1
    assert version.json()["status"] == "draft"
    assert version.json()["is_immutable"] is False

    # --- Publish version (template auto-activates) ---
    published = await client.post(
        f"/api/v1/template-versions/{version_id}/publish",
        headers=tenant_headers(TENANT_A),
    )
    assert published.status_code == 200, published.text
    assert published.json()["status"] == "published"
    assert published.json()["is_immutable"] is True

    template_after_publish = await client.get(
        f"/api/v1/templates/{template_id}", headers=tenant_headers(TENANT_A)
    )
    assert template_after_publish.json()["status"] == "active"
    assert template_after_publish.json()["published_version_id"] == version_id

    # --- Explicit (idempotent) activation ---
    activated = await client.post(
        f"/api/v1/templates/{template_id}/activate",
        headers=tenant_headers(TENANT_A),
    )
    assert activated.status_code == 200
    assert activated.json()["status"] == "active"

    # --- Instantiate template into a page ---
    instantiated = await client.post(
        "/api/v1/template-instantiations",
        json={
            "workspace_id": workspace_id,
            "site_id": site["id"],
            "template_id": template_id,
            "page_code": "home",
            "page_slug": "home",
            "page_title": "Home",
        },
        headers=tenant_headers(TENANT_A),
    )
    assert instantiated.status_code == 201, instantiated.text
    body = instantiated.json()
    assert body["page_id"] is not None
    assert body["instantiation"]["status"] == "completed"
    assert body["instantiation"]["template_id"] == template_id
    assert body["instantiation"]["template_version_id"] == version_id
    instantiation_id = body["instantiation"]["id"]

    page = await client.get(
        f"/api/v1/pages/{body['page_id']}", headers=tenant_headers(TENANT_A)
    )
    assert page.status_code == 200
    assert page.json()["code"] == "home"
    assert page.json()["page_type"] == "landing"

    # --- List instantiations ---
    listed = await client.get(
        f"/api/v1/template-instantiations?template_id={template_id}",
        headers=tenant_headers(TENANT_A),
    )
    assert listed.status_code == 200
    assert listed.json()["total"] >= 1
    assert any(
        item["id"] == instantiation_id for item in listed.json()["items"]
    )

    fetched = await client.get(
        f"/api/v1/template-instantiations/{instantiation_id}",
        headers=tenant_headers(TENANT_A),
    )
    assert fetched.status_code == 200
    assert fetched.json()["status"] == "completed"

    events = {e.event_type for e in get_event_publisher().published}
    assert ExperienceEventType.TEMPLATE_CREATED.value in events
    assert ExperienceEventType.TEMPLATE_VERSION_CREATED.value in events
    assert ExperienceEventType.TEMPLATE_VERSION_PUBLISHED.value in events
    assert ExperienceEventType.TEMPLATE_ACTIVATED.value in events
    assert ExperienceEventType.TEMPLATE_INSTANTIATED.value in events
    assert ExperienceEventType.PAGE_CREATED.value in events


@pytest.mark.asyncio
async def test_template_tenant_isolation(client):
    ws = await _workspace(client, code="ws-tpl-iso")
    template = await client.post(
        "/api/v1/templates",
        json={
            "workspace_id": ws["id"],
            "code": "iso-tpl",
            "name": "Iso Template",
            "page_type": "landing",
        },
        headers=tenant_headers(TENANT_A),
    )
    assert template.status_code == 201, template.text
    template_id = template.json()["id"]

    other = await client.get(
        f"/api/v1/templates/{template_id}",
        headers=tenant_headers(TENANT_B),
    )
    assert other.status_code == 404

    missing = await client.get("/api/v1/templates")
    assert missing.status_code in (400, 422)


@pytest.mark.asyncio
async def test_immutable_published_version_update_blocked(client):
    ws = await _workspace(client, code="ws-tpl-lock")
    workspace_id = ws["id"]

    template = await client.post(
        "/api/v1/templates",
        json={
            "workspace_id": workspace_id,
            "code": "lock-tpl",
            "name": "Lock Template",
            "page_type": "landing",
        },
        headers=tenant_headers(TENANT_A),
    )
    template_id = template.json()["id"]

    version = await client.post(
        "/api/v1/template-versions",
        json={
            "workspace_id": workspace_id,
            "template_id": template_id,
            "blueprint_json": {"page_type": "landing"},
        },
        headers=tenant_headers(TENANT_A),
    )
    version_id = version.json()["id"]
    version_number = version.json()["version"]

    await client.post(
        f"/api/v1/template-versions/{version_id}/publish",
        headers=tenant_headers(TENANT_A),
    )

    blocked = await client.patch(
        f"/api/v1/template-versions/{version_id}",
        json={"changelog": "should not work", "version": version_number + 1},
        headers=tenant_headers(TENANT_A),
    )
    assert blocked.status_code == 409

    unchanged = await client.get(
        f"/api/v1/template-versions/{version_id}", headers=tenant_headers(TENANT_A)
    )
    assert unchanged.json()["changelog"] != "should not work"
    assert unchanged.json()["is_immutable"] is True
