"""igraph integration — convert AGE graphs to igraph Graph objects."""

from __future__ import annotations

import json
from typing import TYPE_CHECKING, Any

from piggie.exceptions import IntegrationError

if TYPE_CHECKING:
    import igraph as ig

    from piggie.driver import PiggieDriver


def to_igraph_sql(
    driver: PiggieDriver,
    graph: str,
    *,
    directed: bool = True,
    node_properties: bool = True,
) -> tuple[ig.Graph, dict[int, int]]:
    """Convert an AGE graph to igraph via direct SQL reads.

    Bypasses Cypher planning and agtype parsing by reading AGE's internal
    label tables directly. igraph uses 0-based consecutive vertex indices,
    so we build a mapping from AGE bigint IDs to igraph indices.

    Args:
        driver: Connected PiggieDriver.
        graph: Graph name.
        directed: If True, return a directed graph.
        node_properties: Include vertex properties as vertex attributes.

    Returns:
        Tuple of (igraph.Graph, id_map) where id_map maps
        igraph vertex index → AGE bigint ID.
    """
    try:
        import igraph as ig
    except ImportError:
        raise ImportError(
            "igraph is required. Install with: pip install piggie[igraph]"
        ) from None

    conn = driver.connection
    schema = driver.get_schema(graph=graph)

    # Phase 1: collect all nodes
    nodes: list[tuple[int, str, dict[str, Any]]] = []
    for label_info in schema["vertex_labels"]:
        label = label_info["name"]
        try:
            with conn.cursor() as cur:
                if node_properties:
                    cur.execute(
                        f'SELECT id::text::bigint, properties::text '
                        f'FROM {graph}."{label}"'
                    )
                    for row in cur:
                        props = json.loads(row[1]) if row[1] else {}
                        nodes.append((row[0], label, props))
                else:
                    cur.execute(
                        f'SELECT id::text::bigint FROM {graph}."{label}"'
                    )
                    for row in cur:
                        nodes.append((row[0], label, {}))
        except Exception as exc:
            raise IntegrationError(
                f"Failed SQL read for vertex label {label}: {exc}"
            ) from exc

    # Build ID mappings
    id_map: dict[int, int] = {}        # igraph_index → age_id
    reverse_map: dict[int, int] = {}   # age_id → igraph_index
    for i, (age_id, _label, _props) in enumerate(nodes):
        id_map[i] = age_id
        reverse_map[age_id] = i

    # Phase 2: collect all edges (mapped to igraph indices)
    edges: list[tuple[int, int]] = []
    for label_info in schema["edge_labels"]:
        label = label_info["name"]
        try:
            with conn.cursor() as cur:
                cur.execute(
                    f'SELECT start_id::text::bigint, end_id::text::bigint '
                    f'FROM {graph}."{label}"'
                )
                for row in cur:
                    src_idx = reverse_map.get(row[0])
                    tgt_idx = reverse_map.get(row[1])
                    if src_idx is not None and tgt_idx is not None:
                        edges.append((src_idx, tgt_idx))
        except Exception as exc:
            raise IntegrationError(
                f"Failed SQL read for edge label {label}: {exc}"
            ) from exc

    # Single constructor call (fastest igraph construction method)
    G = ig.Graph(n=len(nodes), edges=edges, directed=directed)
    G.vs["age_id"] = [n[0] for n in nodes]
    G.vs["label"] = [n[1] for n in nodes]

    return G, id_map
