"""RLM Neo-Cortex -- Component Interface Contracts.

All modules import from here. No module imports another module directly.
Cross-module communication goes through these typed protocols.
"""
from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Any, Dict, List, Optional, Protocol, Tuple
from uuid import UUID


# ---------------------------------------------------------------------------
# Shared constants
# ---------------------------------------------------------------------------

EMBEDDING_DIM: int = 768
"""Qdrant vector dimension (nomic-embed-text / Gemini embedding-001)."""

DEFAULT_DECAY_HALF_LIFE: float = 7.0
"""Default Ebbinghaus decay half-life in days."""

SURPRISE_THRESHOLD: float = 0.50
"""Minimum surprise score to persist a memory (below = DISCARD)."""

MAX_CONTENT_LENGTH: int = 32_000
"""Maximum character length for a single memory content field."""

REDIS_TTL_ENTITLEMENT: int = 300
"""Redis cache TTL for entitlement manifests (seconds)."""


# ---------------------------------------------------------------------------
# Shared enumerations
# ---------------------------------------------------------------------------

class MemoryTier(str, Enum):
    """Memory storage tier based on surprise score."""
    DISCARD = "discard"      # < 0.30 -- not worth storing
    WORKING = "working"      # 0.30-0.50 -- short-term
    EPISODIC = "episodic"    # 0.50-0.80 -- medium-term
    SEMANTIC = "semantic"    # >= 0.80 -- long-term / axiom candidate


class CustomerTier(str, Enum):
    """Subscription tier for billing entitlement."""
    STARTER = "starter"           # $497/mo
    PROFESSIONAL = "professional"  # $997/mo
    ENTERPRISE = "enterprise"     # $1,497/mo
    QUEEN = "queen"               # $20K+/mo (internal only)


class FeedbackSignal(int, Enum):
    """Preference feedback from user."""
    NEGATIVE = -1
    NEUTRAL = 0
    POSITIVE = 1


# ---------------------------------------------------------------------------
# Shared data classes
# ---------------------------------------------------------------------------

@dataclass
class MemoryRecord:
    """A single memory item flowing through the gateway."""
    tenant_id: UUID
    content: str
    source: str
    domain: str
    surprise_score: float = 0.0
    memory_tier: MemoryTier = MemoryTier.WORKING
    metadata: Dict[str, Any] = field(default_factory=dict)
    created_at: datetime = field(default_factory=datetime.utcnow)
    vector_id: Optional[str] = None
    pg_id: Optional[int] = None


@dataclass
class EntitlementManifest:
    """Capability manifest for a specific tenant."""
    tenant_id: UUID
    tier: CustomerTier
    memory_limit_mb: int = 100          # MB of vector storage
    max_memories_per_day: int = 500
    decay_policy: str = "moderate"      # aggressive | moderate | conservative | infinite
    allowed_mcp_tools: List[str] = field(default_factory=list)
    features: Dict[str, bool] = field(default_factory=dict)


@dataclass
class PreferencePair:
    """A single preference pair for DPO training."""
    input_text: str
    chosen_output: str
    rejected_output: str
    annotator_id: str = "telegram_feedback"
    confidence: float = 1.0
    metadata: Dict[str, Any] = field(default_factory=dict)


# ---------------------------------------------------------------------------
# Protocol definitions (interfaces)
# ---------------------------------------------------------------------------

class MemoryGatewayProtocol(Protocol):
    """Contract for Module 1: Memory Gateway."""

    async def write_memory(
        self, tenant_id: UUID, content: str, source: str, domain: str,
        metadata: Optional[Dict[str, Any]] = None,
    ) -> MemoryRecord: ...

    async def read_memories(
        self, tenant_id: UUID, query: str, limit: int = 10,
    ) -> List[MemoryRecord]: ...

    async def delete_memory(
        self, tenant_id: UUID, memory_id: str,
    ) -> bool: ...

    async def search_memories(
        self, tenant_id: UUID, query: str, limit: int = 10,
        min_score: float = 0.0,
    ) -> List[MemoryRecord]: ...


class EntitlementLedgerProtocol(Protocol):
    """Contract for Module 2: Entitlement Ledger."""

    async def get_manifest(self, tenant_id: UUID) -> EntitlementManifest: ...

    async def update_tier(
        self, tenant_id: UUID, new_tier: CustomerTier,
    ) -> EntitlementManifest: ...

    async def check_quota(
        self, tenant_id: UUID, operation: str,
    ) -> bool: ...


class SurpriseIntegrationProtocol(Protocol):
    """Contract for Module 3: Surprise Integration."""

    def score_content(
        self, content: str, source: str, domain: str,
    ) -> Tuple[float, MemoryTier]: ...


class DecaySchedulerProtocol(Protocol):
    """Contract for Module 4: Ebbinghaus Decay Scheduler."""

    async def run_decay_cycle(
        self, tenant_id: Optional[UUID] = None,
    ) -> Dict[str, int]: ...

    async def get_decay_stats(
        self, tenant_id: Optional[UUID] = None,
    ) -> Dict[str, Any]: ...


class FeedbackCollectorProtocol(Protocol):
    """Contract for Module 5: Feedback Collection Pipeline."""

    async def record_feedback(
        self, tenant_id: UUID, interaction_id: str,
        signal: FeedbackSignal, context: Optional[Dict] = None,
    ) -> PreferencePair: ...

    async def get_pair_count(self) -> int: ...


class TenantPartitionProtocol(Protocol):
    """Contract for Module 6: Tenant Partitioning."""

    async def create_tenant(
        self, tenant_id: UUID, tier: CustomerTier,
    ) -> bool: ...

    async def delete_tenant_data(
        self, tenant_id: UUID, cryptographic_shred: bool = False,
    ) -> Dict[str, int]: ...

    async def verify_isolation(
        self, tenant_a: UUID, tenant_b: UUID,
    ) -> bool: ...
