# app/modules/loyalty/tests/conftest.py
"""
Module-specific fixtures for loyalty tests.
Core fixtures (db, client, etc.) are inherited from the root conftest.py.
"""

import uuid
from datetime import UTC, datetime

import pytest

from app.api.deps import get_current_merchant_api, get_merchant_for_current_user
from app.modules.loyalty.models import LoyaltyCard, LoyaltyProgram
from app.modules.loyalty.models.loyalty_program import LoyaltyType
from app.modules.tenancy.models import Merchant, Platform, Store, User
from app.modules.tenancy.models.store import StoreUser
from app.modules.tenancy.models.store_platform import StorePlatform
from app.modules.tenancy.schemas.auth import UserContext
from main import app


@pytest.fixture
def loyalty_platform(db):
    """Create a platform for loyalty store tests."""
    platform = Platform(
        code=f"loyalty_{uuid.uuid4().hex[:8]}",
        name="Loyalty Test Platform",
        is_active=True,
    )
    db.add(platform)
    db.commit()
    db.refresh(platform)
    return platform


@pytest.fixture
def loyalty_store_setup(db, loyalty_platform):
    """
    Full store setup for loyalty integration tests.

    Creates: User -> Merchant -> Store -> StoreUser -> StorePlatform
             + LoyaltyProgram + LoyaltyCard (with customer)

    Returns dict with all objects for easy access.
    """
    from app.modules.customers.models.customer import Customer
    from middleware.auth import AuthManager

    auth = AuthManager()
    uid = uuid.uuid4().hex[:8]

    # Owner user
    owner = User(
        email=f"loyaltyowner_{uid}@test.com",
        username=f"loyaltyowner_{uid}",
        hashed_password=auth.hash_password("storepass123"),
        role="merchant_owner",
        is_active=True,
        is_email_verified=True,
    )
    db.add(owner)
    db.commit()
    db.refresh(owner)

    # Merchant
    merchant = Merchant(
        name=f"Loyalty Merchant {uid}",
        owner_user_id=owner.id,
        contact_email=owner.email,
        is_active=True,
        is_verified=True,
    )
    db.add(merchant)
    db.commit()
    db.refresh(merchant)

    # Store
    store = Store(
        merchant_id=merchant.id,
        store_code=f"LOYTEST_{uid.upper()}",
        subdomain=f"loytest{uid}",
        name=f"Loyalty Test Store {uid}",
        is_active=True,
        is_verified=True,
    )
    db.add(store)
    db.commit()
    db.refresh(store)

    # StoreUser
    store_user = StoreUser(
        store_id=store.id,
        user_id=owner.id,
        is_active=True,
    )
    db.add(store_user)
    db.commit()

    # StorePlatform
    sp = StorePlatform(
        store_id=store.id,
        platform_id=loyalty_platform.id,
    )
    db.add(sp)
    db.commit()

    # Customer
    customer = Customer(
        email=f"customer_{uid}@test.com",
        first_name="Test",
        last_name="Customer",
        hashed_password="!test!unused",  # noqa: SEC-001
        customer_number=f"CUST-{uid.upper()}",
        store_id=store.id,
        is_active=True,
    )
    db.add(customer)
    db.commit()
    db.refresh(customer)

    # Loyalty Program
    program = LoyaltyProgram(
        merchant_id=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=0,
        max_daily_stamps=10,
        require_staff_pin=False,
        card_name="Test Rewards",
        card_color="#4F46E5",
        is_active=True,
        points_rewards=[
            {"id": "reward_1", "name": "€5 off", "points_required": 100, "is_active": True},
        ],
    )
    db.add(program)
    db.commit()
    db.refresh(program)

    # Loyalty Card
    card = LoyaltyCard(
        merchant_id=merchant.id,
        program_id=program.id,
        customer_id=customer.id,
        enrolled_at_store_id=store.id,
        card_number=f"TESTCARD-{uid.upper()}",
        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 {
        "owner": owner,
        "merchant": merchant,
        "store": store,
        "platform": loyalty_platform,
        "customer": customer,
        "program": program,
        "card": card,
    }


@pytest.fixture
def loyalty_merchant_setup(db, loyalty_platform):
    """
    Merchant-only setup for loyalty integration tests (no program).

    Creates: User -> Merchant (no program yet).
    Use this for testing program creation via merchant API.
    """
    from middleware.auth import AuthManager

    auth = AuthManager()
    uid = uuid.uuid4().hex[:8]

    owner = User(
        email=f"merchowner_{uid}@test.com",
        username=f"merchowner_{uid}",
        hashed_password=auth.hash_password("merchpass123"),
        role="merchant_owner",
        is_active=True,
        is_email_verified=True,
    )
    db.add(owner)
    db.commit()
    db.refresh(owner)

    merchant = Merchant(
        name=f"Loyalty Merchant {uid}",
        owner_user_id=owner.id,
        contact_email=owner.email,
        is_active=True,
        is_verified=True,
    )
    db.add(merchant)
    db.commit()
    db.refresh(merchant)

    return {
        "owner": owner,
        "merchant": merchant,
    }


@pytest.fixture
def loyalty_merchant_headers(loyalty_store_setup):
    """
    Override auth dependencies to return merchant/user for the merchant owner.
    Uses the full loyalty_store_setup which includes a program.
    """
    owner = loyalty_store_setup["owner"]
    merchant = loyalty_store_setup["merchant"]

    user_context = UserContext(
        id=owner.id,
        email=owner.email,
        username=owner.username,
        role="merchant_owner",
        is_active=True,
    )

    app.dependency_overrides[get_merchant_for_current_user] = lambda: merchant
    app.dependency_overrides[get_current_merchant_api] = lambda: user_context
    yield {"Authorization": "Bearer fake-token"}
    app.dependency_overrides.pop(get_merchant_for_current_user, None)
    app.dependency_overrides.pop(get_current_merchant_api, None)


@pytest.fixture
def loyalty_merchant_headers_no_program(loyalty_merchant_setup):
    """
    Override auth dependencies for a merchant that has no program yet.
    """
    owner = loyalty_merchant_setup["owner"]
    merchant = loyalty_merchant_setup["merchant"]

    user_context = UserContext(
        id=owner.id,
        email=owner.email,
        username=owner.username,
        role="merchant_owner",
        is_active=True,
    )

    app.dependency_overrides[get_merchant_for_current_user] = lambda: merchant
    app.dependency_overrides[get_current_merchant_api] = lambda: user_context
    yield {"Authorization": "Bearer fake-token"}
    app.dependency_overrides.pop(get_merchant_for_current_user, None)
    app.dependency_overrides.pop(get_current_merchant_api, None)


@pytest.fixture
def loyalty_store_headers(client, loyalty_store_setup):
    """
    Get real JWT auth headers by logging in via store auth endpoint.
    """
    owner = loyalty_store_setup["owner"]
    response = client.post(
        "/api/v1/store/auth/login",
        json={
            "email_or_username": owner.username,
            "password": "storepass123",
        },
    )
    assert response.status_code == 200, f"Store login failed: {response.text}"
    token = response.json()["access_token"]
    return {"Authorization": f"Bearer {token}"}
