"""
Cache model for storing expensive operation results.
"""

from datetime import datetime, timedelta, UTC
from functools import partial

from sqlalchemy import JSON, Column, Index, Integer, String, Text
from sqlalchemy_utc import UtcDateTime

from .base import Base


class Cache(Base):
    """
    Cache for API responses and expensive operations.
    Helps reduce API calls and improve performance.
    """

    __tablename__ = "cache"

    id = Column(Integer, primary_key=True)
    cache_key = Column(String(255), unique=True, nullable=False, index=True)
    cache_value = Column(JSON)  # For structured data
    cache_text = Column(Text)  # For large text content

    # Cache metadata
    cache_type = Column(
        String(50)
    )  # api_response, computation, search_result, etc.
    source = Column(String(100))  # openai, google, computation, etc.
    size_bytes = Column(Integer)  # Size of cached data

    # Expiration
    ttl_seconds = Column(Integer)  # Time to live in seconds
    expires_at = Column(UtcDateTime, index=True)

    # Usage tracking
    hit_count = Column(Integer, default=0)
    created_at = Column(UtcDateTime, default=partial(datetime.now, UTC))
    accessed_at = Column(UtcDateTime, default=partial(datetime.now, UTC))

    # Indexes for performance
    __table_args__ = (
        Index("idx_type_expires", "cache_type", "expires_at"),
        Index("idx_source_key", "source", "cache_key"),
    )

    def is_expired(self) -> bool:
        """Check if cache entry has expired."""
        if not self.expires_at:
            return False

        # Handle both timezone-aware and naive datetimes
        now = datetime.now(UTC)
        expires = self.expires_at

        # If expires_at is naive, make it aware (assuming UTC)
        if expires.tzinfo is None:
            expires = expires.replace(tzinfo=UTC)

        return now > expires

    def set_ttl(self, seconds: int):
        """Set time to live for cache entry."""
        self.ttl_seconds = seconds
        self.expires_at = datetime.now(UTC) + timedelta(seconds=seconds)

    def record_hit(self):
        """Record a cache hit."""
        self.hit_count += 1
        self.accessed_at = datetime.now(UTC)

    def __repr__(self):
        expired = " (expired)" if self.is_expired() else ""
        return f"<Cache(key='{self.cache_key}', type='{self.cache_type}', hits={self.hit_count}{expired})>"


class SearchCache(Base):
    """Search cache for storing query results with TTL and LRU eviction."""

    __tablename__ = "search_cache"

    query_hash = Column(String, primary_key=True)
    query_text = Column(Text, nullable=False)
    results = Column(
        JSON, nullable=False
    )  # JSON column for automatic serialization
    created_at = Column(Integer, nullable=False)  # Unix timestamp
    expires_at = Column(Integer, nullable=False)  # Unix timestamp
    access_count = Column(Integer, default=1)
    last_accessed = Column(Integer, nullable=False)  # Unix timestamp

    __table_args__ = (
        Index("idx_expires_at", "expires_at"),
        Index("idx_last_accessed", "last_accessed"),
    )

    def __repr__(self):
        return f"<SearchCache(query_text='{self.query_text[:50]}...', expires_at={self.expires_at})>"
