"""
Data models for L3 relation triplets.

A relation triplet is the fundamental unit of the relation graph:
  Subject --[Predicate]--> Object

Each triplet is stored as a markdown file in ``output/relations/``.
"""

from dataclasses import dataclass, field
from typing import List, Optional


# Controlled relation vocabulary — maps semantic class to VSM channel
RELATION_TYPES = {
    "enables": "S1 → S1",
    "constrains": "S1 ← S1",
    "regulates": "S3 → S1",
    "is regulated by": "S1 ← S3",
    "coordinates": "S2",
    "produces": "S1",
    "consumes": "S1",
    "monitors": "S3*",
    "audits": "S3*",
    "adapts to": "S4",
    "anticipates": "S4",
    "defines": "S5 → any",
    "is defined by": "any ← S5",
    "contradicts": "any",
    "tensions with": "any",
}


@dataclass
class RelationMeta:
    """Structured metadata for a single relation triplet.

    Attributes:
        slug:          Unique identifier, e.g.
                       ``division_of_labour--constrains--market_extent``
        subject:       Human-readable title of the subject entity
        subject_slug:  Slug of the subject entity (links to L1)
        predicate:     Human-readable predicate phrase, e.g. "limited by"
        object:        Human-readable title of the object entity
        object_slug:   Slug of the object entity (links to L1)
        relation_type: Semantic class from the controlled vocabulary
        vsm_channel:   VSM systems involved, e.g. "S1 → S2"
        evidence:      Source text quote or chapter reference
        feedback_role: Description of role in a feedback loop (if any)
        source_path:   Absolute path to the ``.md`` file
    """

    slug: str
    subject: str
    subject_slug: str
    predicate: str
    object: str
    object_slug: str
    relation_type: str
    vsm_channel: str
    evidence: str = ""
    feedback_role: str = ""
    source_path: str = ""

    @property
    def is_feedback_member(self) -> bool:
        """True if this relation participates in a named feedback loop."""
        return bool(self.feedback_role.strip())

    def edge(self) -> tuple:
        """Return a (subject_slug, object_slug, predicate) edge tuple."""
        return (self.subject_slug, self.object_slug, self.predicate)
