"""Point ledger repositories — Phase 7.2."""
from __future__ import annotations

from uuid import UUID

from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession

from app.models.ledger import PointLedgerEntry
from app.models.types import LedgerEntryType
from app.repositories.base import TenantBaseRepository


class PointLedgerRepository(TenantBaseRepository[PointLedgerEntry]):
    model = PointLedgerEntry

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

    async def balance_for_account(self, tenant_id: UUID, point_account_id: UUID) -> int:
        stmt = select(func.coalesce(func.sum(PointLedgerEntry.amount), 0)).where(
            PointLedgerEntry.tenant_id == tenant_id,
            PointLedgerEntry.point_account_id == point_account_id,
        )
        result = await self.session.execute(stmt)
        return int(result.scalar_one())

    async def list_for_account(
        self,
        tenant_id: UUID,
        point_account_id: UUID,
        *,
        entry_type: LedgerEntryType | None = None,
        offset: int = 0,
        limit: int = 50,
        q: str | None = None,
    ):
        clauses = [
            PointLedgerEntry.tenant_id == tenant_id,
            PointLedgerEntry.point_account_id == point_account_id,
        ]
        if entry_type is not None:
            clauses.append(PointLedgerEntry.entry_type == entry_type)
        if q:
            like = f"%{q.strip()}%"
            clauses.append(
                (PointLedgerEntry.reason.ilike(like))
                | (PointLedgerEntry.reference_id.ilike(like))
                | (PointLedgerEntry.idempotency_key.ilike(like))
            )
        stmt = (
            select(PointLedgerEntry)
            .where(*clauses)
            .order_by(PointLedgerEntry.created_at.desc())
            .offset(offset)
            .limit(limit)
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()

    async def count_for_account(
        self,
        tenant_id: UUID,
        point_account_id: UUID,
        *,
        entry_type: LedgerEntryType | None = None,
        q: str | None = None,
    ) -> int:
        clauses = [
            PointLedgerEntry.tenant_id == tenant_id,
            PointLedgerEntry.point_account_id == point_account_id,
        ]
        if entry_type is not None:
            clauses.append(PointLedgerEntry.entry_type == entry_type)
        if q:
            like = f"%{q.strip()}%"
            clauses.append(
                (PointLedgerEntry.reason.ilike(like))
                | (PointLedgerEntry.reference_id.ilike(like))
            )
        stmt = select(func.count()).select_from(PointLedgerEntry).where(*clauses)
        result = await self.session.execute(stmt)
        return int(result.scalar_one())
