"""Quota helpers for per-tenant limits."""

from __future__ import annotations

from typing import Iterable

from fastapi import HTTPException, status

from hieromem_core.memory import Memory
from hieromem_api.instrumentation.prometheus import record_quota_violation
from hieromem_api.settings import get_settings
from hieromem_api.tenants import Tenant, resolve_tenant


def _tenant_namespace_prefix(tenant: Tenant) -> str:
    return f"{tenant.tenant_id}::"


def _namespaces(memory: Memory) -> Iterable[str]:
    if getattr(memory, "_multi_tenant", False):
        return list(getattr(memory, "_episodes_by_namespace", {}).keys())
    return [getattr(memory, "namespace", "default")]


def get_namespace_count(memory: Memory, tenant: Tenant | object) -> int:
    """Return how many namespaces currently exist for the tenant."""

    tenant = resolve_tenant(tenant)
    if not tenant.enforce_namespace_isolation:
        return 1
    prefix = _tenant_namespace_prefix(tenant)
    return sum(1 for ns in _namespaces(memory) if ns.startswith(prefix))


def get_episode_count(memory: Memory, tenant: Tenant | object) -> int:
    """Return number of stored episodes for the tenant."""

    tenant = resolve_tenant(tenant)
    if not getattr(memory, "_multi_tenant", False):
        return len(memory.episodes)

    total = 0
    prefix = _tenant_namespace_prefix(tenant)
    all_namespaces = getattr(memory, "_episodes_by_namespace", {})
    for namespace, episodes in all_namespaces.items():
        if tenant.enforce_namespace_isolation and not namespace.startswith(
                prefix):
            continue
        total += len(episodes)
    return total


def _limit(value: int | None, default: int) -> int:
    if value is None:
        return default
    return int(value)


def enforce_write_quotas(
        memory: Memory,
        tenant: Tenant | object,
        *,
        namespace_exists: bool) -> None:
    settings = get_settings()
    tenant = resolve_tenant(tenant)
    max_episodes = _limit(tenant.max_episodes,
                          settings.default_max_episodes_per_tenant)
    if max_episodes > 0 and get_episode_count(memory, tenant) >= max_episodes:
        record_quota_violation(tenant.tenant_id, "episode")
        raise HTTPException(
            status_code=status.HTTP_429_TOO_MANY_REQUESTS,
            detail="episode quota exceeded for tenant",
        )

    if tenant.enforce_namespace_isolation:
        max_namespaces = _limit(
            tenant.max_namespaces, settings.default_max_namespaces_per_tenant
        )
        if max_namespaces > 0 and (not namespace_exists) and (
            get_namespace_count(memory, tenant) >= max_namespaces
        ):
            record_quota_violation(tenant.tenant_id, "namespace")
            raise HTTPException(
                status_code=status.HTTP_429_TOO_MANY_REQUESTS,
                detail="namespace quota exceeded for tenant",
            )


__all__ = [
    "get_episode_count",
    "get_namespace_count",
    "enforce_write_quotas",
]
