"""Machine and Asset relationship models."""

from shopdb.extensions import db
from .base import BaseModel


class RelationshipType(BaseModel):
    """
    Types of relationships between assets.

    ADR-001 seeds three canonical types: partof, controls, connectedto.
    Sites may add legacy/communication-flavored types (Serial Cable, Direct
    Ethernet, USB, WiFi, Dualpath) for backward compatibility with pre-1.0
    data, but new ADR-001 code paths only reason about the three canonical
    types via free-text label for nuance.
    """
    __tablename__ = 'relationshiptypes'

    relationshiptypeid = db.Column(db.Integer, primary_key=True)
    relationshiptype = db.Column(db.String(50), unique=True, nullable=False)
    description = db.Column(db.Text)
    color = db.Column(db.String(20), comment='CSS color for relationship badges')

    # Sibling propagation (ADR-001): when a relationship of this type is
    # created/deleted, the framework finds all assets related to the source
    # via the type at propagatesthroughid and mirrors the change. Null means
    # no propagation. Seeded values:
    #   partof       -> null (propagation rail itself)
    #   controls     -> partof (controls propagates across siblings)
    #   connectedto  -> null (network paths don't propagate)
    propagatesthroughid = db.Column(
        db.Integer,
        db.ForeignKey('relationshiptypes.relationshiptypeid'),
        nullable=True,
        comment='Sibling-propagation rail per ADR-001'
    )

    propagatesthrough = db.relationship(
        'RelationshipType',
        remote_side=[relationshiptypeid],
        foreign_keys=[propagatesthroughid],
    )

    def __repr__(self):
        return f"<RelationshipType {self.relationshiptype}>"


class AssetRelationship(BaseModel):
    """
    Relationships between assets.

    Examples:
    - Computer controls Equipment
    - Two machines are dualpath partners
    - Network device connects to equipment
    """
    __tablename__ = 'assetrelationships'

    relationshipid = db.Column(db.Integer, primary_key=True)

    sourceassetid = db.Column(
        db.Integer,
        db.ForeignKey('assets.assetid'),
        nullable=False
    )
    targetassetid = db.Column(
        db.Integer,
        db.ForeignKey('assets.assetid'),
        nullable=False
    )
    relationshiptypeid = db.Column(
        db.Integer,
        db.ForeignKey('relationshiptypes.relationshiptypeid'),
        nullable=False
    )

    # Free-text description carrying domain nuance ("DNC feed",
    # "operator workstation", "ethernet PoE"). Avoids inflating type list.
    label = db.Column(db.String(200), comment='Free-text relationship description (ADR-001)')

    # When true, resolve_asset_position walks across this edge (priority 2
    # in the resolution chain). Defaults to true for partof + controls when
    # the relationship is created via the API; nullable for legacy rows.
    inheritsposition = db.Column(
        db.Boolean,
        default=True,
        nullable=False,
        server_default='1',
        comment='If true, resolved-position walk follows this edge (ADR-001)'
    )

    notes = db.Column(db.Text)

    sourceasset = db.relationship(
        'Asset',
        foreign_keys=[sourceassetid],
        backref='outgoing_relationships'
    )
    targetasset = db.relationship(
        'Asset',
        foreign_keys=[targetassetid],
        backref='incoming_relationships'
    )
    relationshiptype = db.relationship('RelationshipType', backref='asset_relationships')

    __table_args__ = (
        db.UniqueConstraint(
            'sourceassetid',
            'targetassetid',
            'relationshiptypeid',
            name='uq_asset_relationship'
        ),
        db.Index('idx_asset_rel_source', 'sourceassetid'),
        db.Index('idx_asset_rel_target', 'targetassetid'),
    )

    def __repr__(self):
        return f"<AssetRelationship {self.sourceassetid} -> {self.targetassetid}>"
