"""
Fixtures for promocode and promo group testing
"""

from datetime import UTC, datetime, timedelta
from types import SimpleNamespace
from unittest.mock import AsyncMock

import pytest

from app.database.models import PromoCodeType


@pytest.fixture
def sample_promo_group():
    """Sample PromoGroup object for testing"""
    return SimpleNamespace(
        id=1,
        name='Test VIP Group',
        priority=50,
        server_discount_percent=20,
        traffic_discount_percent=15,
        device_discount_percent=10,
        period_discounts={30: 10, 60: 15, 90: 20},
        is_default=False,
        auto_assign_total_spent_kopeks=None,
        auto_assign_enabled=False,
        addon_discount_enabled=True,
    )


@pytest.fixture
def sample_user():
    """Sample User object for testing"""
    return SimpleNamespace(
        id=1,
        telegram_id=123456789,
        username='testuser',
        full_name='Test User',
        balance_kopeks=0,
        language='ru',
        has_had_paid_subscription=False,
        total_spent_kopeks=0,
    )


@pytest.fixture
def sample_promocode_balance():
    """Balance type promocode"""
    return SimpleNamespace(
        id=1,
        code='BALANCE100',
        type=PromoCodeType.BALANCE.value,
        balance_bonus_kopeks=10000,  # 100 rubles
        subscription_days=0,
        max_uses=100,
        current_uses=10,
        is_active=True,
        promo_group_id=None,
        promo_group=None,
        valid_until=None,
        created_at=datetime.now(UTC),
        updated_at=datetime.now(UTC),
        created_by=1,
    )


@pytest.fixture
def sample_promocode_subscription():
    """Subscription days type promocode"""
    return SimpleNamespace(
        id=2,
        code='SUB30',
        type=PromoCodeType.SUBSCRIPTION_DAYS.value,
        balance_bonus_kopeks=0,
        subscription_days=30,
        max_uses=50,
        current_uses=5,
        is_active=True,
        promo_group_id=None,
        promo_group=None,
        valid_until=datetime.now(UTC) + timedelta(days=60),
        created_at=datetime.now(UTC),
        updated_at=datetime.now(UTC),
        created_by=1,
    )


@pytest.fixture
def sample_promocode_promo_group(sample_promo_group):
    """Promo group type promocode"""
    return SimpleNamespace(
        id=3,
        code='VIPGROUP',
        type=PromoCodeType.PROMO_GROUP.value,
        balance_bonus_kopeks=0,
        subscription_days=0,
        max_uses=100,
        current_uses=20,
        is_active=True,
        promo_group_id=sample_promo_group.id,
        promo_group=sample_promo_group,
        valid_until=None,
        created_at=datetime.now(UTC),
        updated_at=datetime.now(UTC),
        created_by=1,
    )


@pytest.fixture
def sample_promocode_invalid():
    """Invalid/expired promocode"""
    return SimpleNamespace(
        id=4,
        code='EXPIRED',
        type=PromoCodeType.BALANCE.value,
        balance_bonus_kopeks=5000,
        subscription_days=0,
        max_uses=10,
        current_uses=10,  # Used up
        is_active=False,
        promo_group_id=None,
        promo_group=None,
        valid_until=datetime.now(UTC) - timedelta(days=1),  # Expired
        created_at=datetime.now(UTC) - timedelta(days=30),
        updated_at=datetime.now(UTC),
        created_by=1,
    )


@pytest.fixture
def mock_db_session():
    """Mock AsyncSession"""
    db = AsyncMock()
    db.commit = AsyncMock()
    db.rollback = AsyncMock()
    db.refresh = AsyncMock()
    db.get = AsyncMock()
    db.execute = AsyncMock()
    db.add = AsyncMock()
    return db


@pytest.fixture
def mock_has_user_promo_group():
    """Mock has_user_promo_group function"""
    return AsyncMock(return_value=False)


@pytest.fixture
def mock_add_user_to_promo_group():
    """Mock add_user_to_promo_group function"""
    return AsyncMock()


@pytest.fixture
def mock_get_promo_group_by_id(sample_promo_group):
    """Mock get_promo_group_by_id function"""
    return AsyncMock(return_value=sample_promo_group)


@pytest.fixture
def mock_get_user_by_id(sample_user):
    """Mock get_user_by_id function"""
    return AsyncMock(return_value=sample_user)


@pytest.fixture
def mock_get_promocode_by_code():
    """Mock get_promocode_by_code function"""
    return AsyncMock()


@pytest.fixture
def mock_check_user_promocode_usage():
    """Mock check_user_promocode_usage function"""
    return AsyncMock(return_value=False)


@pytest.fixture
def mock_create_promocode_use():
    """Mock create_promocode_use function"""
    return AsyncMock()


@pytest.fixture
def mock_remnawave_service():
    """Mock RemnaWaveService"""
    service = AsyncMock()
    service.create_remnawave_user = AsyncMock()
    service.update_remnawave_user = AsyncMock()
    return service


@pytest.fixture
def mock_subscription_service():
    """Mock SubscriptionService"""
    service = AsyncMock()
    service.create_remnawave_user = AsyncMock()
    service.update_remnawave_user = AsyncMock()
    return service


# Helper function to create a valid promocode property mock
def make_promocode_valid(promocode):
    """Helper to make promocode appear valid (is_valid property)"""
    promocode.is_valid = True
    return promocode
