"""Localization, RTL/LTR & media-ref API tests — Phase 11.5."""
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-loc"):
    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()


async def _locale_profile(client, workspace_id: str, *, code="fa", language="fa", direction="rtl"):
    resp = await client.post(
        "/api/v1/locale-profiles",
        json={
            "workspace_id": workspace_id,
            "code": code,
            "name": f"Locale {code}",
            "language": language,
            "text_direction": direction,
            "status": "active",
        },
        headers=tenant_headers(TENANT_A),
    )
    assert resp.status_code == 201, resp.text
    return resp.json()


@pytest.mark.asyncio
async def test_health_phase_115(client):
    """Prior phase localization capabilities remain intact after 11.6."""
    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"]["site_locale_bindings"] is True
    assert body["features"]["localizations"] is True
    assert body["features"]["rtl_ltr"] is True
    assert body["features"]["media_refs"] is True
    assert body["features"]["storage_media_refs_only"] is True
    assert body["features"]["forms"] is True
    assert body["features"]["surveys"] is True
    assert body["features"]["templates"] is True
    assert "rtl" in body["text_directions"]
    assert "ltr" in body["text_directions"]
    assert body["phase"] == "11.10"
    assert body["version"].startswith("0.11.10")


@pytest.mark.asyncio
async def test_site_locale_binding_and_localization_lifecycle(client):
    ws = await _workspace(client)
    workspace_id = ws["id"]
    site = await _site(client, workspace_id)
    fa = await _locale_profile(client, workspace_id, code="fa", language="fa", direction="rtl")
    en = await _locale_profile(
        client, workspace_id, code="en", language="en", direction="ltr"
    )

    binding = await client.post(
        "/api/v1/site-locale-bindings",
        json={
            "workspace_id": workspace_id,
            "site_id": site["id"],
            "locale_profile_id": fa["id"],
            "is_default": True,
        },
        headers=tenant_headers(TENANT_A),
    )
    assert binding.status_code == 201, binding.text
    binding_body = binding.json()
    assert binding_body["locale_code"] == "fa"
    assert binding_body["text_direction"] == "rtl"
    assert binding_body["is_default"] is True

    second = await client.post(
        "/api/v1/site-locale-bindings",
        json={
            "workspace_id": workspace_id,
            "site_id": site["id"],
            "locale_profile_id": en["id"],
            "text_direction": "ltr",
            "is_default": True,
            "sort_order": 1,
        },
        headers=tenant_headers(TENANT_A),
    )
    assert second.status_code == 201, second.text
    assert second.json()["is_default"] is True

    # Previous default cleared
    fa_after = await client.get(
        f"/api/v1/site-locale-bindings/{binding_body['id']}",
        headers=tenant_headers(TENANT_A),
    )
    assert fa_after.json()["is_default"] is False

    loc = await client.post(
        "/api/v1/localizations",
        json={
            "workspace_id": workspace_id,
            "target_type": "site",
            "target_id": site["id"],
            "locale": "fa",
            "text_direction": "rtl",
            "title": "سایت اصلی",
            "summary": "خلاصه فارسی",
            "content_json": {"hero": "سلام"},
            "status": "active",
        },
        headers=tenant_headers(TENANT_A),
    )
    assert loc.status_code == 201, loc.text
    loc_id = loc.json()["id"]
    assert loc.json()["text_direction"] == "rtl"

    upsert = await client.post(
        "/api/v1/localizations",
        json={
            "workspace_id": workspace_id,
            "target_type": "site",
            "target_id": site["id"],
            "locale": "fa",
            "text_direction": "rtl",
            "title": "سایت به‌روز",
            "status": "active",
            "version": loc.json()["version"],
        },
        headers=tenant_headers(TENANT_A),
    )
    assert upsert.status_code == 201, upsert.text
    assert upsert.json()["id"] == loc_id
    assert upsert.json()["title"] == "سایت به‌روز"
    assert upsert.json()["version"] == loc.json()["version"] + 1

    listed = await client.get(
        f"/api/v1/localizations?site_id={site['id']}&locale=fa&q=سایت",
        headers=tenant_headers(TENANT_A),
    )
    # filter uses target_id not site_id — use target filters
    listed = await client.get(
        f"/api/v1/localizations?target_type=site&target_id={site['id']}&q=سایت",
        headers=tenant_headers(TENANT_A),
    )
    assert listed.status_code == 200
    assert listed.json()["total"] >= 1

    events = get_event_publisher().published
    types = {e.event_type for e in events}
    assert ExperienceEventType.SITE_LOCALE_ASSIGNED.value in types
    assert ExperienceEventType.LOCALIZATION_UPSERTED.value in types


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

    created = await client.post(
        "/api/v1/media-refs",
        json={
            "workspace_id": workspace_id,
            "site_id": site["id"],
            "kind": "image",
            "storage_file_ref": "storage://experience/hero.png",
            "alt_text": "Hero",
            "locale": "fa",
            "text_direction": "rtl",
        },
        headers=tenant_headers(TENANT_A),
    )
    assert created.status_code == 201, created.text
    body = created.json()
    assert body["storage_file_ref"] == "storage://experience/hero.png"
    assert "binary" not in body
    assert "blob" not in body

    rejected = await client.post(
        "/api/v1/media-refs",
        json={
            "workspace_id": workspace_id,
            "kind": "image",
            "storage_file_ref": "data:image/png;base64,AAAA",
        },
        headers=tenant_headers(TENANT_A),
    )
    assert rejected.status_code == 422, rejected.text

    rejected_meta = await client.post(
        "/api/v1/media-refs",
        json={
            "workspace_id": workspace_id,
            "kind": "image",
            "storage_file_ref": "storage://ok.png",
            "metadata_json": {"base64": "AAAA"},
        },
        headers=tenant_headers(TENANT_A),
    )
    assert rejected_meta.status_code == 422, rejected_meta.text

    # Tenant isolation
    other = await client.get(
        f"/api/v1/media-refs/{body['id']}",
        headers=tenant_headers(TENANT_B),
    )
    assert other.status_code == 404

    listed = await client.get(
        f"/api/v1/media-refs?workspace_id={workspace_id}&kind=image",
        headers=tenant_headers(TENANT_A),
    )
    assert listed.status_code == 200
    assert listed.json()["total"] >= 1

    events = get_event_publisher().published
    assert any(
        e.event_type == ExperienceEventType.MEDIA_REF_CREATED.value for e in events
    )


@pytest.mark.asyncio
async def test_media_ref_model_has_no_binary_columns():
    from app.models.localization import ExperienceMediaRef

    columns = set(ExperienceMediaRef.__table__.columns.keys())
    forbidden = {
        "binary",
        "blob",
        "bytes",
        "content_bytes",
        "file_bytes",
        "base64",
        "data_uri",
        "raw_content",
    }
    assert forbidden.isdisjoint(columns)
    assert "storage_file_ref" in columns
