"""Integration tests for app.api.v1.domains — domain center, trends, hot-domains."""

import uuid
import datetime

import pytest
import pytest_asyncio
from sqlalchemy import select

from app.models.literature import GlobalTag, GlobalLiterature, GlobalLiteratureTag
from app.models.interaction import UserSubscription
from app.models.user import Tenant, UserTenant


@pytest_asyncio.fixture
async def auth_ctx(client):
    """Register a user and return (headers, user_id)."""
    email = f"t{uuid.uuid4().hex[:6]}@test.cn"
    resp = await client.post("/api/v1/auth/register", json={
        "email": email, "password": "Test1234", "display_name": "TestUser",
    })
    assert resp.status_code == 200
    data = resp.json()
    headers = {"Authorization": f"Bearer {data['token']['access_token']}"}
    user_id = uuid.UUID(data["user"]["id"])
    return headers, user_id


@pytest_asyncio.fixture
async def seed_tag_data(db):
    """Seed tags, literature, and tag-links for domain tests. Cleans up first."""
    from sqlalchemy import delete as sql_delete
    await db.execute(sql_delete(GlobalLiteratureTag))
    await db.execute(sql_delete(GlobalLiterature).where(GlobalLiterature.pmid.in_([90000910])))
    await db.execute(sql_delete(GlobalTag).where(GlobalTag.path.in_(["cancer::lung", "cancer::breast"])))

    tag1 = GlobalTag(
        id=uuid.uuid4(), name_zh="肺癌", name_en="lung cancer",
        path="cancer::lung", tag_category="cancer", level=2,
    )
    tag2 = GlobalTag(
        id=uuid.uuid4(), name_zh="乳腺癌", name_en="breast cancer",
        path="cancer::breast", tag_category="cancer", level=2,
    )
    db.add_all([tag1, tag2])
    await db.flush()

    lit = GlobalLiterature(
        id=uuid.uuid4(), pmid=90000910, title="Lung cancer study",
        abstract="A study about lung cancer", authors=[{"family": "Lee"}],
        journal="JCO", doi="10.1000/jco.001",
        pub_date=datetime.date(2024, 6, 1), pub_year=2024,
    )
    db.add(lit)
    await db.flush()

    # Link literature to tag1
    glt = GlobalLiteratureTag(literature_id=lit.id, tag_id=tag1.id, is_major=True)
    db.add(glt)
    await db.commit()
    return {"tags": [tag1, tag2], "literature": lit}


@pytest_asyncio.fixture
async def seed_subscription(auth_ctx, db, seed_tag_data):
    """Subscribe user to tag1."""
    headers, uid = auth_ctx
    tag1 = seed_tag_data["tags"][0]

    r = await db.execute(
        select(Tenant.id).join(UserTenant).where(UserTenant.user_id == uid)
    )
    tenant_id = r.scalar()

    sub = UserSubscription(
        id=uuid.uuid4(), user_id=uid, tenant_id=tenant_id,
        tag_id=tag1.id, match_mode="standard", is_active=True,
    )
    db.add(sub)
    await db.commit()
    return headers, uid, seed_tag_data


# ── Domain Center ──


@pytest.mark.asyncio
async def test_domain_center_no_subscriptions(client, auth_ctx):
    """Domain center returns empty when no subscriptions."""
    headers, _ = auth_ctx
    r = await client.get("/api/v1/domains/center", headers=headers)
    assert r.status_code == 200
    data = r.json()
    assert data["domains"] == []
    assert data["by_category"] == {}
    assert data["total_subscriptions"] == 0


@pytest.mark.asyncio
async def test_domain_center_with_subscriptions(client, seed_subscription):
    """Domain center returns subscribed domain info."""
    headers, _, seed_data = seed_subscription
    r = await client.get("/api/v1/domains/center", headers=headers)
    assert r.status_code == 200
    data = r.json()
    assert data["total_subscriptions"] == 1
    assert data["domains"][0]["name"] == "肺癌"
    assert data["domains"][0]["category"] == "cancer"
    assert data["domains"][0]["match_mode"] == "standard"


# ── Trends ──


@pytest.mark.asyncio
async def test_domain_trends(client, auth_ctx, seed_tag_data):
    """Domain trends returns weekly data."""
    headers, _ = auth_ctx
    tag_id = str(seed_tag_data["tags"][0].id)
    r = await client.get(f"/api/v1/domains/trends/{tag_id}?weeks=4", headers=headers)
    assert r.status_code == 200
    data = r.json()
    assert data["tag_id"] == tag_id
    assert data["tag_name"] == "肺癌"
    assert len(data["trends"]) == 4
    assert data["total"] >= 0  # may be 0 for old weeks


@pytest.mark.asyncio
async def test_domain_trends_min_weeks(client, auth_ctx, seed_tag_data):
    """Domain trends respect min weeks constraint."""
    headers, _ = auth_ctx
    tag_id = str(seed_tag_data["tags"][0].id)
    r = await client.get(f"/api/v1/domains/trends/{tag_id}?weeks=1", headers=headers)
    assert r.status_code == 200
    data = r.json()
    assert len(data["trends"]) == 1


@pytest.mark.asyncio
async def test_public_domain_trends(client, seed_tag_data):
    """Public domain trends works without auth."""
    tag_id = str(seed_tag_data["tags"][0].id)
    r = await client.get(f"/api/v1/domains/trends/public/{tag_id}?weeks=4")
    assert r.status_code == 200
    data = r.json()
    assert data["tag_name"] == "肺癌"
    assert len(data["trends"]) == 4


@pytest.mark.asyncio
async def test_public_domain_trends_unknown_tag(client):
    """Public trends for non-existent tag returns empty name."""
    r = await client.get(f"/api/v1/domains/trends/public/{uuid.uuid4()}?weeks=4")
    assert r.status_code == 200
    data = r.json()
    assert data["tag_name"] == ""
    assert len(data["trends"]) == 4


# ── Hot Domains ──


@pytest.mark.asyncio
async def test_hot_domains(client, seed_tag_data):
    """Hot domains returns trending tags."""
    r = await client.get("/api/v1/domains/hot-domains")
    assert r.status_code == 200
    data = r.json()
    assert "items" in data
    assert "total" in data
    # May have items from seed_tag_data (level=2 tags)
    if data["items"]:
        assert "name" in data["items"][0]
        assert "weekly_count" in data["items"][0]


@pytest.mark.asyncio
async def test_hot_domains_no_data(client):
    """Hot domains returns empty when no tags meet criteria."""
    r = await client.get("/api/v1/domains/hot-domains")
    assert r.status_code == 200
    data = r.json()
    # Level-2 tags may not exist yet
    assert "items" in data
