"""DAG resolution for remediation patches."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from complyform.core.assessor.control_matcher import Finding
    from complyform.core.remediator.patch_generator import PatchFile


@dataclass
class NewDependencyResource:
    """A new supporting resource required by remediation patches."""

    resource_type: str
    resource_name: str
    required_by_controls: list[str]
    risk_level: str  # "low" | "medium" | "high"
    review_hint: str


@dataclass
class DependencyReport:
    """Summary of new dependency resources."""

    new_resources: list[NewDependencyResource] = field(default_factory=list)


class DependencyResolver:
    """Topologically sort patches by dependency order."""

    def resolve(
        self,
        patches: list[PatchFile],
    ) -> list[PatchFile]:
        """Sort patches so dependencies come first.

        Deduplicates dependency resources. Returns patches in
        dependency-first order.
        """
        has_deps: list[PatchFile] = []
        no_deps: list[PatchFile] = []

        for p in patches:
            if p.dependencies:
                has_deps.append(p)
            else:
                no_deps.append(p)

        # Dependency patches come after no-dep patches
        # (deps are generated inline, so order is:
        #  patches without deps first, then patches with deps)
        return no_deps + has_deps


def build_dependency_report(
    patches: list[PatchFile],
    findings: list[Finding],
) -> DependencyReport | None:
    """Build a report of new dependency resources.

    Returns None if no new dependencies.
    """
    seen: dict[str, NewDependencyResource] = {}
    risk_hints = {
        "low": "Low risk — standard supporting resource.",
        "medium": "Medium risk — review configuration carefully.",
        "high": (
            "HIGH RISK — this resource may affect security"
            " posture. Manual review strongly recommended."
        ),
    }

    for patch in patches:
        for dep_addr in patch.dependencies:
            if dep_addr in seen:
                seen[dep_addr].required_by_controls.append(patch.control_id)
            else:
                parts = dep_addr.split(".", 1)
                rt = parts[0] if parts else dep_addr
                rn = parts[1] if len(parts) > 1 else dep_addr
                seen[dep_addr] = NewDependencyResource(
                    resource_type=rt,
                    resource_name=rn,
                    required_by_controls=[patch.control_id],
                    risk_level=patch.risk_level,
                    review_hint=risk_hints.get(
                        patch.risk_level,
                        risk_hints["low"],
                    ),
                )

    if not seen:
        return None

    return DependencyReport(
        new_resources=list(seen.values()),
    )
