from sqlalchemy import select
from app.models.reward import Reward
from app.models.customer import Customer
from app.models.wallet import Wallet
from app.models.wallet_history import WalletHistory
from app.models.redemption import Redemption
from app.core.exceptions import not_found, bad_request, conflict

class RewardService:
    @staticmethod
    async def redeem(db, brand_id, customer_id, reward_id, idempotency_key):
        existing = await db.scalar(select(Redemption).where(Redemption.idempotency_key == idempotency_key))
        if existing: return existing
        customer = await db.scalar(select(Customer).where(Customer.id == customer_id, Customer.brand_id == brand_id))
        reward = await db.scalar(select(Reward).where(Reward.id == reward_id, Reward.brand_id == brand_id, Reward.status == "active").with_for_update())
        if not customer: raise not_found("Customer not found")
        if not reward: raise not_found("Reward not found")
        if reward.stock <= 0: raise bad_request("Reward out of stock")
        wallet = await db.scalar(select(Wallet).where(Wallet.customer_id == customer_id, Wallet.brand_id == brand_id).with_for_update())
        if not wallet or wallet.balance < reward.points_cost: raise bad_request("Insufficient points")
        wallet.balance -= reward.points_cost
        customer.points_balance = wallet.balance
        reward.stock -= 1
        redemption = Redemption(brand_id=brand_id, customer_id=customer_id, reward_id=reward_id, points_spent=reward.points_cost, idempotency_key=idempotency_key)
        db.add(redemption)
        await db.flush()
        db.add(WalletHistory(
            brand_id=brand_id, wallet_id=wallet.id, customer_id=customer_id,
            entry_type="debit", points=-reward.points_cost, balance_after=wallet.balance,
            reference_type="redemption", reference_id=str(redemption.id),
            description=f"Reward redemption: {reward.name}"
        ))
        await db.commit()
        await db.refresh(redemption)
        return redemption
