"""Webhook history retention tasks."""

from __future__ import annotations

from collections import defaultdict
from datetime import datetime, timedelta
import logging
from typing import Dict, Iterable, List

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

from ..config.tier_limits import get_tier_config, normalize_tier_name
from ..db import AsyncSessionLocal
from ..model_defs.webhook_models import InboundWebhook
from ..models import AccountEntitlements

logger = logging.getLogger(__name__)


def _retention_days_for_tier(tier_name: str) -> int:
    normalized = normalize_tier_name(tier_name)
    try:
        tier_config = get_tier_config(normalized)
        return max(1, int(tier_config.webhook_history_retention_days or 1))
    except Exception:  # noqa: BLE001 - defensive fallback
        return 1


def _group_accounts_by_retention_days(
    rows: Iterable[tuple[str, str]]
) -> Dict[int, List[str]]:
    grouped: Dict[int, List[str]] = defaultdict(list)
    for account_id, tier in rows:
        if not account_id:
            continue
        grouped[_retention_days_for_tier(tier)].append(str(account_id))
    return grouped


async def purge_expired_webhook_history_with_session(
    session: AsyncSession,
    *,
    now: datetime | None = None,
) -> int:
    """Delete webhook history rows outside each account's retention window."""
    current = now or datetime.utcnow()
    entitlements = (
        await session.execute(
            select(AccountEntitlements.account_id, AccountEntitlements.tier)
        )
    ).all()
    grouped = _group_accounts_by_retention_days(entitlements)

    deleted_total = 0
    for retention_days, account_ids in grouped.items():
        if not account_ids:
            continue
        cutoff = current - timedelta(days=retention_days)
        result = await session.execute(
            delete(InboundWebhook).where(
                InboundWebhook.source == "sheet_webhook",
                InboundWebhook.account_id.in_(account_ids),
                InboundWebhook.received_at < cutoff,
            )
        )
        deleted_total += int(result.rowcount or 0)

    await session.commit()
    return deleted_total


async def purge_expired_webhook_history() -> int:
    """Scheduled task entrypoint for webhook history retention cleanup."""
    async with AsyncSessionLocal() as session:
        try:
            deleted = await purge_expired_webhook_history_with_session(session)
            logger.info(
                "Webhook history retention purge completed: deleted_rows=%s",
                deleted,
            )
            return deleted
        except Exception:
            await session.rollback()
            logger.exception("Webhook history retention purge failed")
            raise

