"""Usage tracking system for monitoring and enforcing tier-based quotas."""

from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime
from functools import lru_cache
from pathlib import Path
from typing import Optional

from hieromem_api.settings import get_settings
from hieromem_api.usage_store import UsageStore, SQLiteUsageStore, RedisUsageStore


@dataclass
class UsageStats:
    """Usage statistics for a tenant."""

    tenant_id: str
    memories_this_month: int = 0
    recalls_today: int = 0
    recalls_this_month: int = 0
    namespaces_count: int = 0
    last_updated: Optional[datetime] = None


class UsageTracker:
    """Track memory operations per tenant with monthly/daily quotas."""

    def __init__(self, store: UsageStore) -> None:
        self._store = store

    def _get_current_period(self, period_type: str = "month") -> str:
        """Get current period string (e.g., '2025-01' for month, '2025-01-15' for day)."""
        now = datetime.utcnow()
        if period_type == "month":
            return now.strftime("%Y-%m")
        elif period_type == "day":
            return now.strftime("%Y-%m-%d")
        else:
            raise ValueError(f"Invalid period_type: {period_type}")

    def record_remember(self, tenant_id: str) -> None:
        """Record a memory storage operation."""
        self._increment_counter(tenant_id, "remember", "month")

    def record_recall(self, tenant_id: str) -> None:
        """Record a memory recall operation."""
        self._increment_counter(tenant_id, "recall", "day")
        self._increment_counter(tenant_id, "recall", "month")

    def _increment_counter(
        self, tenant_id: str, operation: str, period_type: str
    ) -> None:
        """Increment usage counter for a tenant/operation/period."""
        period = self._get_current_period(period_type)
        self._store.increment_counter(tenant_id, operation, period, period_type)

    def get_usage(self, tenant_id: str) -> UsageStats:
        """Get current usage statistics for a tenant."""
        month_period = self._get_current_period("month")
        day_period = self._get_current_period("day")

        memories_this_month = self._store.get_count(
            tenant_id, "remember", month_period, "month"
        )
        recalls_today = self._store.get_count(tenant_id, "recall", day_period, "day")
        recalls_this_month = self._store.get_count(
            tenant_id, "recall", month_period, "month"
        )

        return UsageStats(
            tenant_id=tenant_id,
            memories_this_month=memories_this_month,
            recalls_today=recalls_today,
            recalls_this_month=recalls_this_month,
            last_updated=datetime.utcnow(),
        )

    def check_quota(self, tenant_id: str, operation: str, limit: Optional[int]) -> bool:
        """
        Check if tenant is within quota for an operation.

        Args:
            tenant_id: Tenant identifier
            operation: 'remember' or 'recall'
            limit: Maximum allowed operations (None = unlimited)

        Returns:
            True if within quota, False if exceeded
        """
        if limit is None:
            return True  # Unlimited

        stats = self.get_usage(tenant_id)

        if operation == "remember":
            return stats.memories_this_month < limit
        elif operation == "recall":
            return stats.recalls_today < limit
        else:
            raise ValueError(f"Invalid operation: {operation}")

    def reset_monthly_counters(self) -> None:
        """Reset monthly counters (should be run via cron on 1st of month)."""
        # Note: We don't actually delete old data, we just let the period-based
        # queries naturally exclude old periods. This preserves historical data.
        pass

    def get_all_tenant_usage(self) -> dict[str, UsageStats]:
        """Get usage stats for all tenants (admin function)."""
        raw_usage = self._store.get_all_tenant_usage()
        return {tenant_id: self.get_usage(tenant_id) for tenant_id in raw_usage.keys()}


@lru_cache(maxsize=1)
def get_usage_tracker() -> UsageTracker:
    """Get singleton usage tracker instance."""
    settings = get_settings()

    if settings.redis_url:
        store = RedisUsageStore(settings.redis_url)
    else:
        # Store usage DB alongside tenant registry
        db_path = settings.tenant_registry_path or "data/tenants.db"
        usage_db_path = str(Path(db_path).parent / "usage.db")
        store = SQLiteUsageStore(usage_db_path)

    return UsageTracker(store)


__all__ = ["UsageTracker", "UsageStats", "get_usage_tracker"]
