"""
Data models for entity classification (L2 typed entities).

Each entity is assigned an Entity Type (what kind of thing it is) and a
VSM System (which control layer it inhabits).  Both assignments come with
a one-sentence rationale from the LLM, stored alongside the classification.
"""

from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime
from typing import Any, Dict, Optional


#: Controlled vocabulary for entity types.
ENTITY_TYPES = ["Element", "Process", "Relation", "Principle", "Institution"]

#: Controlled vocabulary for VSM system assignments.
VSM_SYSTEMS = ["S1", "S2", "S3", "S3*", "S4", "S5"]


@dataclass
class EntityClassification:
    """L2 classification for a single entity."""

    entity_slug: str
    entity_type: str          # one of ENTITY_TYPES
    vsm_system: str           # one of VSM_SYSTEMS
    type_rationale: str = ""  # one sentence
    vsm_rationale: str = ""   # one sentence
    classified_by: str = ""   # model name
    classified_at: Optional[datetime] = None

    # Optional — only set when entity_type == "Relation"
    links_subject: str = ""        # human-readable title of entity A
    links_subject_slug: str = ""   # slug of entity A
    links_object: str = ""         # human-readable title of entity B
    links_object_slug: str = ""    # slug of entity B
    links_mechanism: str = ""      # one sentence: how A and B are connected

    def to_dict(self) -> Dict[str, Any]:
        d: Dict[str, Any] = {
            "entity_slug": self.entity_slug,
            "entity_type": self.entity_type,
            "vsm_system": self.vsm_system,
        }
        if self.type_rationale:
            d["type_rationale"] = self.type_rationale
        if self.vsm_rationale:
            d["vsm_rationale"] = self.vsm_rationale
        if self.classified_by:
            d["classified_by"] = self.classified_by
        if self.classified_at is not None:
            d["classified_at"] = self.classified_at.isoformat()
        if self.links_subject:
            d["links_subject"] = self.links_subject
        if self.links_subject_slug:
            d["links_subject_slug"] = self.links_subject_slug
        if self.links_object:
            d["links_object"] = self.links_object
        if self.links_object_slug:
            d["links_object_slug"] = self.links_object_slug
        if self.links_mechanism:
            d["links_mechanism"] = self.links_mechanism
        return d

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "EntityClassification":
        classified_at: Optional[datetime] = None
        if "classified_at" in data:
            classified_at = datetime.fromisoformat(data["classified_at"])
        return cls(
            entity_slug=data["entity_slug"],
            entity_type=data["entity_type"],
            vsm_system=data["vsm_system"],
            type_rationale=data.get("type_rationale", ""),
            vsm_rationale=data.get("vsm_rationale", ""),
            classified_by=data.get("classified_by", ""),
            classified_at=classified_at,
            links_subject=data.get("links_subject", ""),
            links_subject_slug=data.get("links_subject_slug", ""),
            links_object=data.get("links_object", ""),
            links_object_slug=data.get("links_object_slug", ""),
            links_mechanism=data.get("links_mechanism", ""),
        )
