"""Reward redemption repositories — Phase 7.3."""
from __future__ import annotations

from uuid import UUID

from sqlalchemy import func, select

from app.models.rewards import RewardRedemption
from app.models.types import RedemptionStatus
from app.repositories.base import TenantBaseRepository

_NON_BLOCKING_STATUSES = (RedemptionStatus.CANCELLED,)


class RewardRedemptionRepository(TenantBaseRepository[RewardRedemption]):
    model = RewardRedemption

    async def get_by_idempotency(
        self, tenant_id: UUID, idempotency_key: str | None
    ) -> RewardRedemption | None:
        if not idempotency_key:
            return None
        stmt = select(RewardRedemption).where(
            RewardRedemption.tenant_id == tenant_id,
            RewardRedemption.idempotency_key == idempotency_key,
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()

    async def count_for_member_reward(
        self,
        tenant_id: UUID,
        member_id: UUID,
        reward_id: UUID,
        *,
        exclude_statuses: tuple[RedemptionStatus, ...] = _NON_BLOCKING_STATUSES,
    ) -> int:
        stmt = (
            select(func.count())
            .select_from(RewardRedemption)
            .where(
                RewardRedemption.tenant_id == tenant_id,
                RewardRedemption.member_id == member_id,
                RewardRedemption.reward_id == reward_id,
                RewardRedemption.status.notin_(exclude_statuses),
            )
        )
        result = await self.session.execute(stmt)
        return int(result.scalar_one())

    async def list(
        self,
        tenant_id: UUID,
        *,
        reward_id: UUID | None = None,
        member_id: UUID | None = None,
        status: RedemptionStatus | None = None,
        offset: int = 0,
        limit: int = 50,
    ):
        clauses = [RewardRedemption.tenant_id == tenant_id]
        if reward_id is not None:
            clauses.append(RewardRedemption.reward_id == reward_id)
        if member_id is not None:
            clauses.append(RewardRedemption.member_id == member_id)
        if status is not None:
            clauses.append(RewardRedemption.status == status)
        stmt = (
            select(RewardRedemption)
            .where(*clauses)
            .order_by(RewardRedemption.created_at.desc())
            .offset(offset)
            .limit(limit)
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()

    async def count(
        self,
        tenant_id: UUID,
        *,
        reward_id: UUID | None = None,
        member_id: UUID | None = None,
        status: RedemptionStatus | None = None,
    ) -> int:
        clauses = [RewardRedemption.tenant_id == tenant_id]
        if reward_id is not None:
            clauses.append(RewardRedemption.reward_id == reward_id)
        if member_id is not None:
            clauses.append(RewardRedemption.member_id == member_id)
        if status is not None:
            clauses.append(RewardRedemption.status == status)
        stmt = select(func.count()).select_from(RewardRedemption).where(*clauses)
        result = await self.session.execute(stmt)
        return int(result.scalar_one())

    async def list_for_member(
        self, tenant_id: UUID, member_id: UUID, *, offset: int = 0, limit: int = 50
    ):
        return await self.list(tenant_id, member_id=member_id, offset=offset, limit=limit)

    async def list_for_reward(
        self, tenant_id: UUID, reward_id: UUID, *, offset: int = 0, limit: int = 50
    ):
        return await self.list(tenant_id, reward_id=reward_id, offset=offset, limit=limit)
