"""What TaxPilot AI remembers.

Memory is not chat history. A transcript tells you what was said; this records
what was *learned* — which document arrived, what a workflow decided and why,
what is still missing, what a client prefers. A workflow resuming after a
restart, or picking up a conversation three weeks later, needs the second.

Per ADR-0001 there is no tenant column anywhere in this module. This process
serves one installation; a customer identifier appearing here would mean
multi-tenancy had crept in.
"""

from __future__ import annotations

import uuid
from dataclasses import dataclass, field
from datetime import UTC, datetime
from enum import StrEnum


class MemoryKind(StrEnum):
    """What sort of thing is being remembered.

    Typed rather than free-text so retrieval can ask for one kind — "what is
    missing for this client" is a different question from "what did we decide",
    and a single undifferentiated pile answers neither well.
    """

    DOCUMENT = "document"
    """A document was received, classified and filed."""

    WORKFLOW = "workflow"
    """A workflow ran: what it did and how it ended."""

    DECISION = "decision"
    """A judgement and its reasoning — the summary a later run should read."""

    MISSING = "missing"
    """Something needed but not yet received. Open until resolved."""

    PREFERENCE = "preference"
    """How this client likes to be dealt with."""

    OBSERVATION = "observation"
    """Anything else worth carrying forward."""


@dataclass(slots=True)
class MemoryRecord:
    """One remembered fact.

    ``content`` is deliberately Level 1 or Level 2 only (ADR-0002). Memory is
    long-lived and is the natural thing to embed and later send to a model for
    reasoning; putting a raw CNIC here would mean Level 3 data leaving the
    installation the first time anyone asked a question about it.
    """

    kind: MemoryKind
    content: str
    client_id: int | None = None
    """The CMS client this concerns, when it concerns one."""

    document_id: int | None = None
    workflow_id: str | None = None
    metadata: dict[str, object] = field(default_factory=dict)
    confidence: float | None = None
    resolved: bool = False
    """Only meaningful for MISSING: whether the gap has since been filled."""

    id: str = field(default_factory=lambda: str(uuid.uuid4()))
    created_at: datetime = field(default_factory=lambda: datetime.now(UTC))

    def __post_init__(self) -> None:
        if not self.content.strip():
            # An empty memory is worse than none: it occupies a retrieval slot
            # and tells a later run nothing.
            raise ValueError("A memory record needs content.")

        if self.confidence is not None and not 0.0 <= self.confidence <= 1.0:
            raise ValueError(f"Confidence must be between 0 and 1, got {self.confidence}.")

    def resolve(self) -> None:
        """Mark a gap as filled.

        Resolved rather than deleted: that a document was once missing is part
        of the account's history, and deleting it loses the fact that the AI
        chased it.
        """
        self.resolved = True

    @property
    def is_open_gap(self) -> bool:
        return self.kind is MemoryKind.MISSING and not self.resolved
