"""
Tests for tier synchronization endpoint.

Tests the /api/v1/admin/sync-tier endpoint that receives tier updates
from Stripe webhooks and syncs them to usage_quota_model.
"""

import pytest
from fastapi.testclient import TestClient
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from fmatch.saas.model_defs.usage_quota_model import UsageQuotaModel


@pytest.mark.asyncio
async def test_sync_tier_creates_new_user(
    test_client: TestClient,
    async_db: AsyncSession,
):
    """Test that sync-tier creates a new quota record for new users."""
    response = test_client.post(
        "/api/v1/admin/sync-tier",
        headers={"Authorization": "Bearer dev-token"},
        json={
            "clerk_user_id": "user_test_new_123",
            "tier": "pro",
            "status": "active",
        },
    )

    assert response.status_code == 200
    data = response.json()
    assert data["ok"] is True
    assert data["updated"] is True
    assert data["tier"] == "pro"
    assert "Created new quota record" in data["message"]

    # Verify record created in database
    stmt = select(UsageQuotaModel).where(
        UsageQuotaModel.account_id == "user_test_new_123"
    )
    result = await async_db.execute(stmt)
    quota = result.scalar_one_or_none()

    assert quota is not None
    assert quota.tier == "pro"
    assert quota.monthly_rows_used == 0
    assert quota.enrichment_credits_used == 0
    assert quota.subscription_status == "active"


@pytest.mark.asyncio
async def test_sync_tier_updates_existing_user(
    test_client: TestClient,
    async_db: AsyncSession,
):
    """Test that sync-tier updates tier for existing users."""
    # Create initial user with free tier
    quota = UsageQuotaModel(
        account_id="user_test_existing_456",
        tier="free",
        monthly_rows_used=100,
        enrichment_credits_used=5,
        subscription_status="active",
    )
    async_db.add(quota)
    await async_db.commit()

    # Sync to unleashed tier
    response = test_client.post(
        "/api/v1/admin/sync-tier",
        headers={"Authorization": "Bearer dev-token"},
        json={
            "clerk_user_id": "user_test_existing_456",
            "tier": "unleashed",
            "status": "active",
        },
    )

    assert response.status_code == 200
    data = response.json()
    assert data["ok"] is True
    assert data["updated"] is True
    assert data["old_tier"] == "free"
    assert data["new_tier"] == "unleashed"
    assert "free" in data["message"]
    assert "unleashed" in data["message"]

    # Verify tier updated but usage preserved
    await async_db.refresh(quota)
    assert quota.tier == "unleashed"
    assert quota.monthly_rows_used == 100  # Usage preserved
    assert quota.enrichment_credits_used == 5  # Usage preserved


@pytest.mark.asyncio
async def test_sync_tier_idempotent(
    test_client: TestClient,
    async_db: AsyncSession,
):
    """Test that syncing same tier twice is idempotent."""
    # Create user
    quota = UsageQuotaModel(
        account_id="user_test_idempotent_789",
        tier="pro",
        monthly_rows_used=200,
        enrichment_credits_used=10,
        subscription_status="active",
    )
    async_db.add(quota)
    await async_db.commit()

    # Sync to same tier
    response = test_client.post(
        "/api/v1/admin/sync-tier",
        headers={"Authorization": "Bearer dev-token"},
        json={
            "clerk_user_id": "user_test_idempotent_789",
            "tier": "pro",
            "status": "active",
        },
    )

    assert response.status_code == 200
    data = response.json()
    assert data["ok"] is True
    assert data["updated"] is False  # No change

    # Verify nothing changed
    await async_db.refresh(quota)
    assert quota.tier == "pro"
    assert quota.monthly_rows_used == 200
    assert quota.enrichment_credits_used == 10


def test_sync_tier_requires_auth(test_client: TestClient):
    """Test that sync-tier requires webhook secret."""
    # No auth header
    response = test_client.post(
        "/api/v1/admin/sync-tier",
        json={
            "clerk_user_id": "user_test_auth",
            "tier": "pro",
            "status": "active",
        },
    )
    assert response.status_code == 401

    # Invalid auth header
    response = test_client.post(
        "/api/v1/admin/sync-tier",
        headers={"Authorization": "Bearer wrong-secret"},
        json={
            "clerk_user_id": "user_test_auth",
            "tier": "pro",
            "status": "active",
        },
    )
    assert response.status_code == 401


def test_sync_tier_validates_tier(test_client: TestClient):
    """Test that sync-tier validates tier values."""
    response = test_client.post(
        "/api/v1/admin/sync-tier",
        headers={"Authorization": "Bearer dev-token"},
        json={
            "clerk_user_id": "user_test_invalid_tier",
            "tier": "invalid_tier",
            "status": "active",
        },
    )

    assert response.status_code == 400
    data = response.json()
    assert "Invalid tier" in data["detail"]


def test_sync_tier_requires_all_fields(test_client: TestClient):
    """Test that sync-tier requires all required fields."""
    # Missing tier
    response = test_client.post(
        "/api/v1/admin/sync-tier",
        headers={"Authorization": "Bearer dev-token"},
        json={
            "clerk_user_id": "user_test_missing_fields",
            "status": "active",
        },
    )
    assert response.status_code == 422  # Validation error

    # Missing status
    response = test_client.post(
        "/api/v1/admin/sync-tier",
        headers={"Authorization": "Bearer dev-token"},
        json={
            "clerk_user_id": "user_test_missing_fields",
            "tier": "pro",
        },
    )
    assert response.status_code == 422


@pytest.mark.asyncio
async def test_sync_tier_preserves_usage_on_downgrade(
    test_client: TestClient,
    async_db: AsyncSession,
):
    """Test that downgrading tier doesn't reset usage counters."""
    # Create user on unleashed tier with usage
    quota = UsageQuotaModel(
        account_id="user_test_downgrade_999",
        tier="unleashed",
        monthly_rows_used=450000,
        enrichment_credits_used=800,
        subscription_status="active",
    )
    async_db.add(quota)
    await async_db.commit()

    # Downgrade to pro
    response = test_client.post(
        "/api/v1/admin/sync-tier",
        headers={"Authorization": "Bearer dev-token"},
        json={
            "clerk_user_id": "user_test_downgrade_999",
            "tier": "pro",
            "status": "active",
        },
    )

    assert response.status_code == 200

    # Verify usage preserved even though user is now over pro limits
    await async_db.refresh(quota)
    assert quota.tier == "pro"
    assert quota.monthly_rows_used == 450000  # Over pro limit, but preserved
    assert quota.enrichment_credits_used == 800


@pytest.mark.asyncio
async def test_sync_tier_handles_canceled_status(
    test_client: TestClient,
    async_db: AsyncSession,
):
    """Test that sync-tier handles canceled subscriptions."""
    quota = UsageQuotaModel(
        account_id="user_test_canceled_111",
        tier="pro",
        monthly_rows_used=50000,
        enrichment_credits_used=50,
        subscription_status="active",
    )
    async_db.add(quota)
    await async_db.commit()

    # Sync with canceled status
    response = test_client.post(
        "/api/v1/admin/sync-tier",
        headers={"Authorization": "Bearer dev-token"},
        json={
            "clerk_user_id": "user_test_canceled_111",
            "tier": "free",
            "status": "canceled",
        },
    )

    assert response.status_code == 200
    data = response.json()
    assert data["new_tier"] == "free"

    # Verify tier updated to free
    await async_db.refresh(quota)
    assert quota.tier == "free"
