# tests/fixtures/loyalty_fixtures.py
"""
Loyalty module test fixtures.

Provides fixtures for:
- Loyalty programs (merchant-based)
- Loyalty cards
- Transactions
- Staff PINs
"""

import uuid
from datetime import UTC, datetime, timedelta

import pytest

from app.modules.loyalty.models import (
    LoyaltyCard,
    LoyaltyProgram,
    LoyaltyTransaction,
    StaffPin,
)
from app.modules.loyalty.models.loyalty_program import LoyaltyType
from app.modules.loyalty.models.loyalty_transaction import TransactionType


@pytest.fixture
def test_loyalty_program(db, test_merchant):
    """Create a test loyalty program for a merchant."""
    program = LoyaltyProgram(
        merchant_id=test_merchant.id,
        loyalty_type=LoyaltyType.POINTS.value,
        points_per_euro=10,
        welcome_bonus_points=50,
        minimum_redemption_points=100,
        minimum_purchase_cents=0,
        points_expiration_days=365,
        cooldown_minutes=15,
        max_daily_stamps=5,
        require_staff_pin=True,
        card_name="Test Rewards",
        card_color="#4F46E5",
        is_active=True,
        points_rewards=[
            {"id": "reward_1", "name": "€5 off", "points_required": 100, "description": "€5 discount"},
            {"id": "reward_2", "name": "€10 off", "points_required": 200, "description": "€10 discount"},
            {"id": "reward_3", "name": "€25 off", "points_required": 500, "description": "€25 discount"},
        ],
    )
    db.add(program)
    db.commit()
    db.refresh(program)
    return program


@pytest.fixture
def test_loyalty_program_no_expiration(db, test_merchant):
    """Create a test loyalty program without point expiration."""
    from app.modules.tenancy.models import Merchant

    unique_id = str(uuid.uuid4())[:8]
    merchant = Merchant(
        name=f"No Expiry Merchant {unique_id}",
        contact_email=f"noexpiry{unique_id}@test.com",
        is_active=True,
    )
    db.add(merchant)
    db.flush()

    program = LoyaltyProgram(
        merchant_id=merchant.id,
        loyalty_type=LoyaltyType.POINTS.value,
        points_per_euro=1,
        welcome_bonus_points=0,
        minimum_redemption_points=50,
        points_expiration_days=None,  # No expiration
        cooldown_minutes=0,
        max_daily_stamps=10,
        require_staff_pin=False,
        card_name="No Expiry Rewards",
        is_active=True,
    )
    db.add(program)
    db.commit()
    db.refresh(program)
    return program


@pytest.fixture
def test_loyalty_card(db, test_loyalty_program, test_customer, test_store):
    """Create a test loyalty card."""
    unique_id = str(uuid.uuid4())[:8].upper()
    card = LoyaltyCard(
        merchant_id=test_loyalty_program.merchant_id,
        program_id=test_loyalty_program.id,
        customer_id=test_customer.id,
        enrolled_at_store_id=test_store.id,
        card_number=f"CARD-{unique_id}",
        points_balance=100,
        total_points_earned=150,
        points_redeemed=50,
        is_active=True,
        last_activity_at=datetime.now(UTC),
    )
    db.add(card)
    db.commit()
    db.refresh(card)
    return card


@pytest.fixture
def test_loyalty_card_inactive(db, test_loyalty_program, test_store):
    """Create a test loyalty card that hasn't been used in a long time (for expiration tests)."""
    unique_id = str(uuid.uuid4())[:8].upper()
    card = LoyaltyCard(
        merchant_id=test_loyalty_program.merchant_id,
        program_id=test_loyalty_program.id,
        customer_id=None,
        enrolled_at_store_id=test_store.id,
        card_number=f"INACTIVE-{unique_id}",
        points_balance=500,
        total_points_earned=500,
        is_active=True,
        # Last activity was 400 days ago (beyond 365-day expiration)
        last_activity_at=datetime.now(UTC) - timedelta(days=400),
    )
    db.add(card)
    db.commit()
    db.refresh(card)
    return card


@pytest.fixture
def test_loyalty_transaction(db, test_loyalty_card, test_store):
    """Create a test loyalty transaction."""
    transaction = LoyaltyTransaction(
        merchant_id=test_loyalty_card.merchant_id,
        card_id=test_loyalty_card.id,
        store_id=test_store.id,
        transaction_type=TransactionType.POINTS_EARNED.value,
        points_delta=50,
        points_balance_after=150,
        stamps_delta=0,
        stamps_balance_after=0,
        notes="Test purchase",
        transaction_at=datetime.now(UTC),
    )
    db.add(transaction)
    db.commit()
    db.refresh(transaction)
    return transaction


@pytest.fixture
def test_staff_pin(db, test_loyalty_program, test_store):
    """Create a test staff PIN."""
    unique_id = str(uuid.uuid4())[:8]
    pin = StaffPin(
        program_id=test_loyalty_program.id,
        merchant_id=test_loyalty_program.merchant_id,
        store_id=test_store.id,
        name=f"Test Staff {unique_id}",
        is_active=True,
    )
    pin.set_pin("1234")
    db.add(pin)
    db.commit()
    db.refresh(pin)
    return pin
