from __future__ import annotations

from collections.abc import Iterable
from datetime import UTC, datetime
from typing import Any

from sqlalchemy import and_, func, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload

from app.database.models import SubscriptionEvent


async def create_subscription_event(
    db: AsyncSession,
    *,
    user_id: int,
    event_type: str,
    subscription_id: int | None = None,
    transaction_id: int | None = None,
    amount_kopeks: int | None = None,
    currency: str | None = None,
    message: str | None = None,
    occurred_at: datetime | None = None,
    extra: dict[str, Any] | None = None,
) -> SubscriptionEvent:
    event = SubscriptionEvent(
        user_id=user_id,
        event_type=event_type,
        subscription_id=subscription_id,
        transaction_id=transaction_id,
        amount_kopeks=amount_kopeks,
        currency=currency,
        message=message,
        occurred_at=occurred_at or datetime.now(UTC),
        extra=extra or None,
    )
    db.add(event)
    await db.commit()
    await db.refresh(event)
    return event


async def list_subscription_events(
    db: AsyncSession,
    *,
    limit: int,
    offset: int,
    event_types: Iterable[str] | None = None,
    user_id: int | None = None,
) -> tuple[list[SubscriptionEvent], int]:
    base_query = select(SubscriptionEvent)
    filters = []

    if event_types:
        filters.append(SubscriptionEvent.event_type.in_(set(event_types)))
    if user_id:
        filters.append(SubscriptionEvent.user_id == user_id)

    if filters:
        base_query = base_query.where(and_(*filters))

    total_query = base_query.with_only_columns(func.count()).order_by(None)
    total = await db.scalar(total_query) or 0

    result = await db.execute(
        base_query.options(selectinload(SubscriptionEvent.user))
        .order_by(SubscriptionEvent.occurred_at.desc())
        .offset(offset)
        .limit(limit)
    )

    return result.scalars().all(), int(total)
