"""Tests for app.core.plans — plan definitions, get_plan, get_tenant_plan, RequireFeature, CheckQuota"""

import pytest
from unittest.mock import AsyncMock, MagicMock

from app.core.tenant_context import tenant_ctx


def test_get_plan_free():
    from app.core.plans import get_plan, PLANS
    plan = get_plan("free")
    assert plan["name"] == "Free"
    assert plan["ai_summary"] is False
    assert plan["max_saved_items"] == 200


def test_get_plan_pro():
    from app.core.plans import get_plan
    plan = get_plan("pro")
    assert plan["name"] == "Pro"
    assert plan["ai_summary"] is True
    assert plan["max_saved_items"] == 10_000


def test_get_plan_team():
    from app.core.plans import get_plan
    plan = get_plan("team")
    assert plan["name"] == "Team"
    assert plan["teams"] is True
    assert plan["max_team_members"] == 100


def test_get_plan_unknown_fallback():
    from app.core.plans import get_plan
    plan = get_plan("nonexistent_plan")
    assert plan["name"] == "Free"  # falls back to free


def test_get_plan_all_keys_present():
    """Every plan has all expected keys"""
    from app.core.plans import get_plan, PLANS
    expected_keys = {"name", "max_storage_mb", "max_literature_items", "max_saved_items",
                     "max_review_inclusions",
                     "api_quota_per_day", "teams", "approval_workflows", "sso",
                     "branding", "max_team_members", "ai_summary", "ai_translate",
                     "export_formats", "review_export", "journal_club"}
    for plan_type in PLANS:
        plan = get_plan(plan_type)
        for key in expected_keys:
            assert key in plan, f"Plan {plan_type} missing key {key}"


@pytest.mark.asyncio
async def test_get_tenant_plan_no_tenant():
    """No tenant context returns Free plan"""
    from app.core.plans import get_tenant_plan
    token = tenant_ctx.set(None)
    try:
        result = await get_tenant_plan(AsyncMock())
    finally:
        tenant_ctx.reset(token)
    assert result["name"] == "Free"


@pytest.mark.asyncio
async def test_get_tenant_plan_with_tenant():
    """Tenant context queries DB for plan_type"""
    from app.core.plans import get_tenant_plan
    mock_db = AsyncMock()
    mock_scalar = MagicMock()
    mock_scalar.scalar.return_value = "pro"
    mock_db.execute.return_value = mock_scalar

    token = tenant_ctx.set("00000000-0000-0000-0000-000000000001")
    try:
        result = await get_tenant_plan(mock_db)
    finally:
        tenant_ctx.reset(token)
    assert result["name"] == "Pro"


@pytest.mark.asyncio
async def test_require_feature_passes():
    """RequireFeature with a feature the plan has returns True"""
    from app.core.plans import RequireFeature
    checker = RequireFeature("ai_summary")
    mock_db = AsyncMock()
    mock_scalar = MagicMock()
    mock_scalar.scalar.return_value = "pro"
    mock_db.execute.return_value = mock_scalar

    token = tenant_ctx.set("00000000-0000-0000-0000-000000000001")
    try:
        result = await checker(db=mock_db)
    finally:
        tenant_ctx.reset(token)
    assert result is True


@pytest.mark.asyncio
async def test_require_feature_fails():
    """RequireFeature with missing feature raises 402"""
    from app.core.plans import RequireFeature
    from fastapi import HTTPException
    checker = RequireFeature("sso")  # Free doesn't have SSO
    mock_db = AsyncMock()
    mock_scalar = MagicMock()
    mock_scalar.scalar.return_value = "free"
    mock_db.execute.return_value = mock_scalar

    token = tenant_ctx.set("00000000-0000-0000-0000-000000000001")
    try:
        with pytest.raises(HTTPException) as exc:
            await checker(db=mock_db)
    finally:
        tenant_ctx.reset(token)
    assert exc.value.status_code == 402


@pytest.mark.asyncio
async def test_check_quota_unlimited():
    """-1 limit returns True without DB query"""
    from app.core.plans import CheckQuota
    checker = CheckQuota("max_saved_items")
    mock_db = AsyncMock()
    mock_scalar = MagicMock()
    mock_scalar.scalar.return_value = "team"  # unlimited
    mock_db.execute.return_value = mock_scalar

    token = tenant_ctx.set("00000000-0000-0000-0000-000000000001")
    try:
        result = await checker(db=mock_db)
    finally:
        tenant_ctx.reset(token)
    assert result is True


@pytest.mark.asyncio
async def test_review_export_free_passes():
    """Free plan has review_export feature (core meta-analysis feature)"""
    from app.core.plans import RequireFeature
    checker = RequireFeature("review_export")
    mock_db = AsyncMock()
    mock_scalar = MagicMock()
    mock_scalar.scalar.return_value = "free"
    mock_db.execute.return_value = mock_scalar

    token = tenant_ctx.set("00000000-0000-0000-0000-000000000001")
    try:
        result = await checker(db=mock_db)
    finally:
        tenant_ctx.reset(token)
    assert result is True


@pytest.mark.asyncio
async def test_review_export_pro_passes():
    """Pro plan has review_export feature"""
    from app.core.plans import RequireFeature
    checker = RequireFeature("review_export")
    mock_db = AsyncMock()
    mock_scalar = MagicMock()
    mock_scalar.scalar.return_value = "pro"
    mock_db.execute.return_value = mock_scalar

    token = tenant_ctx.set("00000000-0000-0000-0000-000000000001")
    try:
        result = await checker(db=mock_db)
    finally:
        tenant_ctx.reset(token)
    assert result is True
