"""Member Management API tests — Phase 9.2."""
from __future__ import annotations

import pytest

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


async def _seed_center_and_type(client, headers):
    center = await client.post(
        "/api/v1/sports-centers",
        json={"code": "m92", "name": "Member Center", "status": "active"},
        headers=headers,
    )
    assert center.status_code == 201, center.text
    center_id = center.json()["id"]
    mtype = await client.post(
        "/api/v1/membership-types",
        json={"sports_center_id": center_id, "code": "std", "name": "Standard"},
        headers=headers,
    )
    assert mtype.status_code == 201, mtype.text
    return center_id, mtype.json()["id"]


@pytest.mark.asyncio
async def test_member_management_happy_path(client):
    headers = tenant_headers(TENANT_A)
    center_id, mtype_id = await _seed_center_and_type(client, headers)

    member = await client.post(
        "/api/v1/members",
        json={
            "sports_center_id": center_id,
            "display_name": "Ali Member",
            "email": "ali@example.com",
            "mobile": "+989121111111",
            "status": "active",
        },
        headers=headers,
    )
    assert member.status_code == 201, member.text
    member_id = member.json()["id"]

    family = await client.post(
        "/api/v1/family-members",
        json={
            "sports_center_id": center_id,
            "member_id": member_id,
            "display_name": "Sara",
            "relationship": "spouse",
            "mobile": "+989122222222",
        },
        headers=headers,
    )
    assert family.status_code == 201, family.text

    emergency = await client.post(
        "/api/v1/emergency-contacts",
        json={
            "sports_center_id": center_id,
            "member_id": member_id,
            "display_name": "Father",
            "phone": "+989123333333",
            "is_primary": True,
        },
        headers=headers,
    )
    assert emergency.status_code == 201, emergency.text

    medical = await client.put(
        "/api/v1/medical-information",
        json={
            "sports_center_id": center_id,
            "member_id": member_id,
            "allergies": ["pollen"],
            "clearance_status": "cleared",
            "document_file_ref": "storage://files/med-1",
        },
        headers=headers,
    )
    assert medical.status_code == 200, medical.text

    membership = await client.post(
        "/api/v1/memberships",
        json={
            "sports_center_id": center_id,
            "membership_type_id": mtype_id,
            "member_id": member_id,
            "display_name": "Ali Member",
            "status": "pending",
        },
        headers=headers,
    )
    assert membership.status_code == 201, membership.text
    membership_id = membership.json()["id"]
    assert membership.json()["member_id"] == member_id

    activated = await client.post(
        f"/api/v1/memberships/{membership_id}/activate",
        json={"version": membership.json()["version"]},
        headers=headers,
    )
    assert activated.status_code == 200, activated.text
    assert activated.json()["status"] == "active"

    frozen = await client.post(
        f"/api/v1/memberships/{membership_id}/freeze",
        json={"version": activated.json()["version"]},
        headers=headers,
    )
    assert frozen.status_code == 200, frozen.text
    assert frozen.json()["status"] == "frozen"

    unfrozen = await client.post(
        f"/api/v1/memberships/{membership_id}/unfreeze",
        json={"version": frozen.json()["version"]},
        headers=headers,
    )
    assert unfrozen.status_code == 200, unfrozen.text
    assert unfrozen.json()["status"] == "active"

    card = await client.post(
        "/api/v1/membership-cards",
        json={
            "sports_center_id": center_id,
            "member_id": member_id,
            "membership_id": membership_id,
            "kind": "qr",
        },
        headers=headers,
    )
    assert card.status_code == 201, card.text
    assert card.json()["qr_payload"]

    digital = await client.post(
        "/api/v1/digital-memberships",
        json={
            "sports_center_id": center_id,
            "member_id": member_id,
            "membership_id": membership_id,
        },
        headers=headers,
    )
    assert digital.status_code == 201, digital.text

    waiver = await client.post(
        "/api/v1/waivers",
        json={
            "sports_center_id": center_id,
            "member_id": member_id,
            "title": "Liability Waiver",
            "document_file_ref": "storage://files/waiver-1",
        },
        headers=headers,
    )
    assert waiver.status_code == 201, waiver.text
    signed = await client.post(
        f"/api/v1/waivers/{waiver.json()['id']}/sign",
        json={"signature_ref": "storage://files/sig-1"},
        headers=headers,
    )
    assert signed.status_code == 200, signed.text
    assert signed.json()["status"] == "signed"

    doc = await client.post(
        "/api/v1/member-documents",
        json={
            "sports_center_id": center_id,
            "member_id": member_id,
            "title": "ID Scan",
            "kind": "id",
            "file_ref": "storage://files/id-1",
        },
        headers=headers,
    )
    assert doc.status_code == 201, doc.text

    events = {e.event_type for e in get_event_publisher().published}
    assert SportsCenterEventType.MEMBER_CREATED.value in events
    assert SportsCenterEventType.MEMBERSHIP_CREATED.value in events
    assert SportsCenterEventType.MEMBERSHIP_FROZEN.value in events
    assert SportsCenterEventType.MEMBERSHIP_UNFROZEN.value in events
    assert SportsCenterEventType.MEMBERSHIP_CARD_ISSUED.value in events
    assert SportsCenterEventType.WAIVER_SIGNED.value in events
    assert SportsCenterEventType.MEMBER_DOCUMENT_ATTACHED.value in events


@pytest.mark.asyncio
async def test_membership_assign_and_tenant_isolation(client):
    headers_a = tenant_headers(TENANT_A)
    headers_b = tenant_headers(TENANT_B)
    center_id, mtype_id = await _seed_center_and_type(client, headers_a)

    member = await client.post(
        "/api/v1/members",
        json={"sports_center_id": center_id, "display_name": "Iso Member"},
        headers=headers_a,
    )
    member_id = member.json()["id"]

    membership = await client.post(
        "/api/v1/memberships",
        json={
            "sports_center_id": center_id,
            "membership_type_id": mtype_id,
            "display_name": "Pending Shell",
            "status": "pending",
        },
        headers=headers_a,
    )
    membership_id = membership.json()["id"]
    assert membership.json()["member_id"] is None

    assigned = await client.post(
        f"/api/v1/memberships/{membership_id}/assign-member",
        json={"member_id": member_id, "version": membership.json()["version"]},
        headers=headers_a,
    )
    assert assigned.status_code == 200, assigned.text
    assert assigned.json()["member_id"] == member_id

    missing = await client.get(
        f"/api/v1/members/{member_id}",
        headers=headers_b,
    )
    assert missing.status_code == 404

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


@pytest.mark.asyncio
async def test_invalid_membership_transition(client):
    headers = tenant_headers(TENANT_A)
    center_id, mtype_id = await _seed_center_and_type(client, headers)
    membership = await client.post(
        "/api/v1/memberships",
        json={
            "sports_center_id": center_id,
            "membership_type_id": mtype_id,
            "display_name": "Pending Only",
            "status": "pending",
        },
        headers=headers,
    )
    bad = await client.post(
        f"/api/v1/memberships/{membership.json()['id']}/freeze",
        json={"version": membership.json()["version"]},
        headers=headers,
    )
    assert bad.status_code == 422


@pytest.mark.asyncio
async def test_capabilities_phase_92(client):
    resp = await client.get("/capabilities")
    assert resp.status_code == 200
    body = resp.json()
    assert body["phase"] == "9.2"
    assert body["version"] == "0.9.2.0"
    assert body["features"]["member_management"] is True
    assert body["features"]["membership_catalog"] is True
