"""DefensiveTechnique and DefensiveTechniqueMapping models.

Stores MITRE D3FEND defensive techniques and their mappings to
ATT&CK techniques, enabling recommended countermeasure lookups.
"""

# Import uuid
import uuid

# Import  from sqlalchemy
from sqlalchemy import (
    Column,
    DateTime,
    ForeignKey,
    Index,
    String,
    Text,
    UniqueConstraint,
    func,
)

# Import UUID from sqlalchemy.dialects.postgresql
from sqlalchemy.dialects.postgresql import UUID

# Import relationship from sqlalchemy.orm
from sqlalchemy.orm import relationship

# Import Base from app.database
from app.database import Base


# Define class DefensiveTechnique
class DefensiveTechnique(Base):
    """MITRE D3FEND defensive technique.

    Represents a countermeasure from the D3FEND framework that can be
    mapped to one or more ATT&CK techniques via DefensiveTechniqueMapping.
    """
    # Assign __tablename__ = "defensive_techniques"
    __tablename__ = "defensive_techniques"

    # Assign id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    # Assign d3fend_id = Column(String, unique=True, nullable=False)          # e.g. "D3-AL"
    d3fend_id = Column(String, unique=True, nullable=False)          # e.g. "D3-AL"
    # Assign name = Column(String, nullable=False)
    name = Column(String, nullable=False)
    # Assign description = Column(Text, nullable=True)
    description = Column(Text, nullable=True)
    # Assign tactic = Column(String, nullable=True)                            # Detect, ...
    tactic = Column(String, nullable=True)                            # Detect, Isolate, Deceive, Evict, etc.
    # Assign d3fend_url = Column(String, nullable=True)
    d3fend_url = Column(String, nullable=True)
    # Assign created_at = Column(DateTime(timezone=True), server_default=func.now())
    created_at = Column(DateTime(timezone=True), server_default=func.now())

    # Relationships
    attack_mappings = relationship(
        # Literal argument value
        "DefensiveTechniqueMapping",
        # Keyword argument: back_populates
        back_populates="defensive_technique",
        # Keyword argument: cascade
        cascade="all, delete-orphan",
    )

    # Assign __table_args__ = (
    __table_args__ = (
        Index('ix_defensive_techniques_tactic', 'tactic'),
    )


# Define class DefensiveTechniqueMapping
class DefensiveTechniqueMapping(Base):
    """Association between a MITRE ATT&CK technique and a D3FEND defensive technique."""
    # Assign __tablename__ = "defensive_technique_mappings"
    __tablename__ = "defensive_technique_mappings"

    # Assign id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    # Assign attack_technique_id = Column(
    attack_technique_id = Column(
        UUID(as_uuid=True),
        ForeignKey("techniques.id", ondelete="CASCADE"),
        # Keyword argument: nullable
        nullable=False,
    )
    # Assign defensive_technique_id = Column(
    defensive_technique_id = Column(
        UUID(as_uuid=True),
        ForeignKey("defensive_techniques.id", ondelete="CASCADE"),
        # Keyword argument: nullable
        nullable=False,
    )

    # Relationships
    attack_technique = relationship("Technique")
    # Assign defensive_technique = relationship("DefensiveTechnique", back_populates="attack_mappings")
    defensive_technique = relationship("DefensiveTechnique", back_populates="attack_mappings")

    # Assign __table_args__ = (
    __table_args__ = (
        Index('ix_dtm_attack_technique', 'attack_technique_id'),
        Index('ix_dtm_defensive_technique', 'defensive_technique_id'),
        UniqueConstraint(
            # Literal argument value
            'attack_technique_id', 'defensive_technique_id',
            # Keyword argument: name
            name='uq_attack_defensive_technique',
        ),
    )
