"""
Graph builder for bridging ephemeral manifest edges to persistent storage.

Bridges RunManifest ephemeral DependencyEdge instances (3-field) to
persistent DependencyEdge storage (6-field), and builds DependencyGraph
from repository data.
"""

from typing import List, Optional, Set

from markitect.prompts.dependencies.models import (
    DependencyEdge,
    DependencyGraph,
    EdgeType,
)
from markitect.prompts.dependencies.repository import IDependencyRepository
from markitect.prompts.execution.manifest import (
    DependencyEdge as ManifestDependencyEdge,
    RunManifest,
)


class GraphBuilder:
    """
    Bridges ephemeral manifest edges to persistent dependency storage.

    Extracts dependency edges from RunManifest instances, persists them
    via IDependencyRepository, and builds in-memory DependencyGraph
    instances for analysis.
    """

    def __init__(self, repository: IDependencyRepository):
        """
        Initialize with dependency repository.

        Args:
            repository: Repository for persisting dependency edges
        """
        self._repository = repository

    def extract_edges(self, manifest: RunManifest) -> List[DependencyEdge]:
        """
        Extract persistent DependencyEdge instances from a RunManifest.

        Converts the ephemeral 3-field DependencyEdge from the manifest
        into persistent 6-field DependencyEdge instances.

        Args:
            manifest: RunManifest containing ephemeral edges

        Returns:
            List of persistent DependencyEdge instances
        """
        edges = []
        for manifest_edge in manifest.dependency_edges:
            edge_type = EdgeType(manifest_edge.edge_type)
            edge = DependencyEdge.create(
                source_artifact_id=manifest_edge.source_id,
                target_artifact_id=manifest_edge.target_id,
                run_id=manifest.run_id,
                edge_type=edge_type,
            )
            edges.append(edge)
        return edges

    def persist_edges(self, manifest: RunManifest) -> List[DependencyEdge]:
        """
        Extract edges from manifest and persist them to the repository.

        Args:
            manifest: RunManifest containing ephemeral edges

        Returns:
            List of persisted DependencyEdge instances
        """
        edges = self.extract_edges(manifest)
        persisted = []
        for edge in edges:
            created = self._repository.create(edge)
            persisted.append(created)
        return persisted

    def build_graph(
        self,
        artifact_ids: Optional[Set[str]] = None,
    ) -> DependencyGraph:
        """
        Build an in-memory DependencyGraph from repository data.

        Args:
            artifact_ids: Optional set of artifact IDs to scope the graph.
                         If None, builds graph from all edges.

        Returns:
            DependencyGraph instance
        """
        graph = DependencyGraph()

        if artifact_ids is not None:
            # Build scoped subgraph
            for artifact_id in artifact_ids:
                edges = self._repository.get_by_source(artifact_id)
                for edge in edges:
                    if edge.target_artifact_id in artifact_ids:
                        graph.add_edge(
                            edge.source_artifact_id,
                            edge.target_artifact_id,
                            edge.edge_type,
                        )
                # Ensure node exists even if it has no edges
                if artifact_id not in graph._forward:
                    graph._forward[artifact_id] = set()
                if artifact_id not in graph._reverse:
                    graph._reverse[artifact_id] = set()
        else:
            # Build full graph
            all_edges = self._repository.get_all()
            for edge in all_edges:
                graph.add_edge(
                    edge.source_artifact_id,
                    edge.target_artifact_id,
                    edge.edge_type,
                )

        return graph

    def build_graph_for_run(self, run_id: str) -> DependencyGraph:
        """
        Build a DependencyGraph from edges of a specific run.

        Args:
            run_id: Run identifier

        Returns:
            DependencyGraph for the run's edges
        """
        graph = DependencyGraph()
        edges = self._repository.get_by_run(run_id)
        for edge in edges:
            graph.add_edge(
                edge.source_artifact_id,
                edge.target_artifact_id,
                edge.edge_type,
            )
        return graph
