"""File-backed graph store adapter (Phase 1 stub)."""

from __future__ import annotations

import json
from pathlib import Path
from typing import Iterable, List, Optional, Tuple

from ..types import GraphNode, GraphEdge


class GraphStoreAdapter:
    """Lightweight file-backed graph store.

    This is a Phase 1 scaffold to enable dual-write and ingestion tests
    without requiring an external graph database.
    """

    def __init__(self, base_dir: Path):
        self.base_dir = Path(base_dir)
        self.base_dir.mkdir(parents=True, exist_ok=True)
        self.nodes_path = self.base_dir / "graph_nodes.jsonl"
        self.edges_path = self.base_dir / "graph_edges.jsonl"

    def upsert_nodes(self, nodes: Iterable[GraphNode]) -> int:
        existing = {n.id: n for n in self._load_nodes()}
        for node in nodes:
            existing[node.id] = node
        self._write_nodes(existing.values())
        return len(nodes)

    def upsert_edges(self, edges: Iterable[GraphEdge]) -> int:
        existing = {self._edge_key(e): e for e in self._load_edges()}
        for edge in edges:
            existing[self._edge_key(edge)] = edge
        self._write_edges(existing.values())
        return len(edges)

    def get_edges(
        self,
        source: Optional[str] = None,
        target: Optional[str] = None,
        edge_type: Optional[str] = None,
    ) -> List[GraphEdge]:
        results = []
        for edge in self._load_edges():
            if source and edge.source != source:
                continue
            if target and edge.target != target:
                continue
            if edge_type and edge.type != edge_type:
                continue
            results.append(edge)
        return results

    def _edge_key(self, edge: GraphEdge) -> Tuple[str, str, str]:
        return (edge.source, edge.target, edge.type)

    def _load_nodes(self) -> List[GraphNode]:
        if not self.nodes_path.exists():
            return []
        items: List[GraphNode] = []
        with self.nodes_path.open("r", encoding="utf-8") as f:
            for line in f:
                line = line.strip()
                if not line:
                    continue
                items.append(GraphNode(**json.loads(line)))
        return items

    def _load_edges(self) -> List[GraphEdge]:
        if not self.edges_path.exists():
            return []
        items: List[GraphEdge] = []
        with self.edges_path.open("r", encoding="utf-8") as f:
            for line in f:
                line = line.strip()
                if not line:
                    continue
                items.append(GraphEdge(**json.loads(line)))
        return items

    def _write_nodes(self, nodes: Iterable[GraphNode]) -> None:
        with self.nodes_path.open("w", encoding="utf-8") as f:
            for node in nodes:
                f.write(node.model_dump_json() + "\n")

    def _write_edges(self, edges: Iterable[GraphEdge]) -> None:
        with self.edges_path.open("w", encoding="utf-8") as f:
            for edge in edges:
                f.write(edge.model_dump_json() + "\n")
