"""Threat actor domain entity with coverage analysis logic.

Pure domain logic — no framework imports.
"""

# Enable future language features for compatibility
from __future__ import annotations

# Import uuid
import uuid

# Import dataclass, field from dataclasses
from dataclasses import dataclass, field

# Import TYPE_CHECKING from typing
from typing import TYPE_CHECKING

# Check: TYPE_CHECKING
if TYPE_CHECKING:
    # Import ThreatActor as ThreatActorORM from app.models.threat_actor
    from app.models.threat_actor import ThreatActor as ThreatActorORM


# Apply the @dataclass decorator
@dataclass
# Define class ThreatActorTechniqueRef
class ThreatActorTechniqueRef:
    """Lightweight reference to a technique used by an actor."""

    # technique_id: uuid.UUID
    technique_id: uuid.UUID
    # Assign mitre_id = None
    mitre_id: str | None = None
    # Assign name = None
    name: str | None = None
    # Assign status = None
    status: str | None = None
    # Assign usage_description = None
    usage_description: str | None = None


# Apply the @dataclass decorator
@dataclass
# Define class ThreatActorEntity
class ThreatActorEntity:
    """Pure domain representation of a MITRE ATT&CK threat actor (group).

    Aggregates references to the techniques the actor is known to use and
    provides coverage analysis properties.
    """

    # name: str
    name: str
    # Assign id = None
    id: uuid.UUID | None = None
    # Assign mitre_id = None
    mitre_id: str | None = None
    # Assign aliases = field(default_factory=list)
    aliases: list[str] = field(default_factory=list)
    # Assign description = None
    description: str | None = None
    # Assign country = None
    country: str | None = None
    # Assign target_sectors = field(default_factory=list)
    target_sectors: list[str] = field(default_factory=list)
    # Assign target_regions = field(default_factory=list)
    target_regions: list[str] = field(default_factory=list)
    # Assign motivation = None
    motivation: str | None = None
    # Assign sophistication = None
    sophistication: str | None = None
    # Assign first_seen = None
    first_seen: str | None = None
    # Assign last_seen = None
    last_seen: str | None = None
    # Assign is_active = True
    is_active: bool = True
    # Assign techniques = field(default_factory=list)
    techniques: list[ThreatActorTechniqueRef] = field(default_factory=list)

    # Apply the @property decorator
    @property
    # Define function technique_count
    def technique_count(self) -> int:
        """Return the total number of techniques associated with this actor.

        Returns:
            int: Count of technique references.
        """
        # Return len(self.techniques)
        return len(self.techniques)

    # Apply the @property decorator
    @property
    # Define function covered_techniques
    def covered_techniques(self) -> list[ThreatActorTechniqueRef]:
        """Return technique references whose coverage status is ``validated`` or ``partial``.

        Returns:
            list[ThreatActorTechniqueRef]: Subset of techniques considered covered.
        """
        # Return [
        return [
            t for t in self.techniques
            if t.status in ("validated", "partial")
        ]

    # Apply the @property decorator
    @property
    # Define function uncovered_techniques
    def uncovered_techniques(self) -> list[ThreatActorTechniqueRef]:
        """Return technique references whose coverage status is neither ``validated`` nor ``partial``.

        Returns:
            list[ThreatActorTechniqueRef]: Subset of techniques not yet covered.
        """
        # Return [
        return [
            t for t in self.techniques
            if t.status not in ("validated", "partial")
        ]

    # Apply the @property decorator
    @property
    # Define function coverage_pct
    def coverage_pct(self) -> float:
        """Return the percentage of the actor's techniques that are covered.

        Returns:
            float: A value from 0.0 to 100.0, rounded to one decimal place.
                Returns 0.0 when the actor has no associated techniques.
        """
        # Check: not self.techniques
        if not self.techniques:
            # Return 0.0
            return 0.0
        # Return round(len(self.covered_techniques) / len(self.techniques) * 100, 1)
        return round(len(self.covered_techniques) / len(self.techniques) * 100, 1)

    # Apply the @classmethod decorator
    @classmethod
    # Define function from_orm
    def from_orm(cls, orm: ThreatActorORM) -> ThreatActorEntity:
        """Build a ThreatActorEntity from a SQLAlchemy ThreatActor model.

        Args:
            orm (ThreatActorORM): The ORM model instance to convert.

        Returns:
            ThreatActorEntity: A fully populated domain entity including
                technique references resolved from the ORM relationship.
        """
        # Assign techs = []
        techs: list[ThreatActorTechniqueRef] = []
        # Iterate over getattr(orm, "techniques", None) or []
        for tat in getattr(orm, "techniques", None) or []:
            # Assign technique = getattr(tat, "technique", None)
            technique = getattr(tat, "technique", None)
            # Call techs.append()
            techs.append(ThreatActorTechniqueRef(
                # Keyword argument: technique_id
                technique_id=tat.technique_id,
                # Keyword argument: mitre_id
                mitre_id=getattr(technique, "mitre_id", None) if technique else None,
                # Keyword argument: name
                name=getattr(technique, "name", None) if technique else None,
                # Keyword argument: status
                status=(
                    technique.status_global.value
                    if technique and hasattr(technique.status_global, "value")
                    else getattr(technique, "status_global", None) if technique else None
                ),
                # Keyword argument: usage_description
                usage_description=tat.usage_description,
            ))
        # Return cls(
        return cls(
            # Keyword argument: id
            id=orm.id,
            # Keyword argument: name
            name=orm.name,
            # Keyword argument: mitre_id
            mitre_id=orm.mitre_id,
            # Keyword argument: aliases
            aliases=orm.aliases or [],
            # Keyword argument: description
            description=orm.description,
            # Keyword argument: country
            country=orm.country,
            # Keyword argument: target_sectors
            target_sectors=orm.target_sectors or [],
            # Keyword argument: target_regions
            target_regions=orm.target_regions or [],
            # Keyword argument: motivation
            motivation=orm.motivation,
            # Keyword argument: sophistication
            sophistication=orm.sophistication,
            # Keyword argument: first_seen
            first_seen=orm.first_seen,
            # Keyword argument: last_seen
            last_seen=orm.last_seen,
            # Keyword argument: is_active
            is_active=orm.is_active if orm.is_active is not None else True,
            # Keyword argument: techniques
            techniques=techs,
        )
