"""
02 — Network creation: Parquet, GeoDataFrames, DataFrame x/y, from_networkx, from_walks.

This example shows different ways to create a Network: from Parquet paths,
from GeoDataFrames (from_gdfs), from a DataFrame with x/y (add_nodes/add_edges),
from a NetworkX graph (from_networkx), and from walk data (from_walks) to infer
observed nodes and edges. It also shows get_nodes() / get_edges().
"""

import shutil
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent))
import pandas as pd
import walkingpandas as wp
from shapely.geometry import Point, LineString

from _data_helpers import make_simple_network_gdf, make_string_id_network_gdf, write_to_temp_parquet


def main():
    print("=" * 60)
    print("02 — Network creation")
    print("=" * 60)

    nodes_gdf, edges_gdf = make_simple_network_gdf()
    walks_df = pd.DataFrame([
        {"walk_id": "w1", "sequence_idx": 0, "node_id": 0, "exit_edge": 0},
        {"walk_id": "w1", "sequence_idx": 1, "node_id": 1, "exit_edge": None},
    ])
    temp_dir = write_to_temp_parquet(nodes_gdf, edges_gdf, walks_df)

    try:
        # --- From Parquet paths ---
        print("\n1. From Parquet paths")
        net1 = wp.Network(
            nodes=temp_dir / "nodes.parquet",
            edges=temp_dir / "edges.parquet",
        )
        nodes_back = net1.get_nodes(as_geopandas=True)
        print(f"   get_nodes(as_geopandas=True) → {len(nodes_back)} nodes")

        # --- From GeoDataFrames ---
        print("\n2. From GeoDataFrames (from_gdfs)")
        net2 = wp.Network.from_gdfs(nodes_gdf, edges_gdf)
        edges_back = net2.get_edges(as_geopandas=False)
        print(f"   get_edges(as_geopandas=False) → {len(edges_back)} edges")

        # --- From DataFrame with x/y (no geometry column) ---
        print("\n3. From DataFrame with x/y")
        nodes_df = nodes_gdf.drop(columns=["geometry"])
        net3 = wp.Network()
        net3.add_nodes(nodes_df)
        net3.add_edges(edges_gdf)
        print("   add_nodes(nodes_df) + add_edges(edges_gdf) → Network ready")

        # --- From NetworkX ---
        print("\n4. From NetworkX")
        try:
            import networkx as nx
            G = nx.DiGraph()
            for _, row in nodes_gdf.iterrows():
                G.add_node(row["node_id"], x=row["geometry"].x, y=row["geometry"].y)
            for _, row in edges_gdf.iterrows():
                G.add_edge(
                    row["source_node"],
                    row["target_node"],
                    edge_id=row["edge_id"],
                )
            net4 = wp.Network.from_networkx(G)
            print(f"   from_networkx(G) → {len(net4.get_nodes())} nodes, {len(net4.get_edges())} edges")
        except ImportError:
            print("   (networkx not installed; skip from_networkx)")

        # --- From walk data (infer observed nodes and edges) ---
        print("\n5. From walk data (from_walks)")
        net5 = wp.Network.from_walks(temp_dir / "walks.parquet")
        n_nodes = len(net5.get_nodes(as_geopandas=False))
        n_edges = len(net5.get_edges(as_geopandas=False))
        print(f"   from_walks(walks.parquet) → {n_nodes} nodes, {n_edges} edges (topology only, no geometry)")

        # --- String node / edge IDs ---
        print("\n6. String IDs (auto-translated to integers under the hood)")
        str_nodes, str_edges = make_string_id_network_gdf()
        net6 = wp.Network()
        net6.add_nodes(str_nodes)
        net6.add_edges(str_edges)
        print(f"   has_string_mapping = {net6.has_string_mapping}")

        # decode=True (default): original string labels
        decoded = net6.get_nodes(as_geopandas=False, decode=True)
        print("   get_nodes(decode=True)  → node_id:", list(decoded["node_id"]))

        # decode=False: raw integers stored in DuckDB
        raw = net6.get_nodes(as_geopandas=False, decode=False)
        print("   get_nodes(decode=False) → node_id:", list(raw["node_id"]))

        # Same for edges
        edges_dec = net6.get_edges(as_geopandas=False, decode=True)
        print("   get_edges(decode=True)  → edge_id:", list(edges_dec["edge_id"]))

        print("\nDone.")
    finally:
        shutil.rmtree(temp_dir, ignore_errors=True)


if __name__ == "__main__":
    main()
