"""Knowledge record model — structured rationale capture."""

from __future__ import annotations

from datetime import datetime, timezone
from enum import Enum

from pydantic import BaseModel, Field

from fliiq.runtime.ulid import generate_id


class RecordType(str, Enum):
    DECISION = "decision"
    CONSTRAINT = "constraint"
    HEURISTIC = "heuristic"
    DOMAIN_RULE = "domain_rule"


class SourceType(str, Enum):
    HUMAN_IN_LOOP = "human_in_loop"
    AGENT_DECISION = "agent_decision"
    AGENT_INFERENCE = "agent_inference"


class Anchor(BaseModel):
    """Optional code anchor for file-bound knowledge."""

    file: str
    line_start: int | None = None
    line_end: int | None = None
    content_hash: str | None = None  # SHA-256 of anchored line range


class Provenance(BaseModel):
    """Where this knowledge came from."""

    source_type: str = ""  # "cli", "repl", "telegram", "job", "email"
    agent_id: str | None = None
    task_id: str | None = None
    interaction_summary: str | None = None


def _utcnow() -> datetime:
    return datetime.now(timezone.utc)


class KnowledgeRecord(BaseModel):
    """A single piece of institutional knowledge."""

    id: str = Field(default_factory=lambda: generate_id("kr"))
    type: RecordType
    source: SourceType
    context: str  # function, module, workflow, or domain area
    decision: str  # what was decided
    rationale: str  # why

    # Optional structured fields
    constraints: list[str] = Field(default_factory=list)
    confidence: float = Field(default=0.8, ge=0.0, le=1.0)
    domain: str = ""
    tags: list[str] = Field(default_factory=list)
    created_at: datetime = Field(default_factory=_utcnow)
    updated_at: datetime = Field(default_factory=_utcnow)
    provenance: Provenance | None = None
    anchor: Anchor | None = None
    alternatives_considered: list[str] = Field(default_factory=list)
    scope: str = ""  # "local", "project", "global"
    expiry_conditions: str = ""
    related_records: list[str] = Field(default_factory=list)
    expired: bool = False
