#!/usr/bin/env python3
"""h_cutoff_network.py
Minimal reproducible implementation of:
1) one-order edge h-cutoff -> h-subnet
2) weak-bridge addition -> h-backbone
3) two-order node h-cutoff -> Hub genes
"""
import argparse
import pandas as pd
import networkx as nx

def continuous_h(values, scale=100.0):
    vals = sorted([float(v)*scale for v in values], reverse=True)
    h = 0
    for i, v in enumerate(vals, start=1):
        if v >= i:
            h = i
        else:
            break
    return h, h/scale

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--edges", required=True, help="CSV with source,target,weight")
    ap.add_argument("--out-prefix", default="hcutoff")
    ap.add_argument("--weak-bridges", type=int, default=5)
    args = ap.parse_args()
    edges = pd.read_csv(args.edges)
    h1, c1 = continuous_h(edges["weight"], 100)
    edges["one_order_status"] = ["h-subnet" if w >= c1 else "candidate-weak-bridge" for w in edges["weight"]]
    G = nx.Graph()
    for _, r in edges.iterrows():
        G.add_edge(r.source, r.target, weight=float(r.weight), distance=1/float(r.weight))
    eb = nx.edge_betweenness_centrality(G, weight="distance", normalized=True)
    maxeb = max(eb.values()) if eb else 1
    edges["edge_betweenness"] = [eb.get(tuple(sorted((r.source, r.target))), eb.get((r.source, r.target), 0))/maxeb for _, r in edges.iterrows()]
    bridge_idx = edges[edges.one_order_status!="h-subnet"].sort_values("edge_betweenness", ascending=False).head(args.weak_bridges).index
    edges["weak_bridge_status"] = ""
    edges.loc[bridge_idx, "weak_bridge_status"] = "weak-bridge"
    edges["backbone_status"] = ["h-backbone" if a=="h-subnet" or b=="weak-bridge" else "background" for a,b in zip(edges.one_order_status, edges.weak_bridge_status)]
    Gb = nx.Graph()
    for _, r in edges[edges.backbone_status=="h-backbone"].iterrows():
        Gb.add_edge(r.source, r.target, weight=float(r.weight))
    deg = dict(Gb.degree())
    strength = dict(Gb.degree(weight="weight"))
    nb = nx.betweenness_centrality(Gb, weight="weight", normalized=True)
    maxdeg = max(deg.values()) if deg else 1
    maxstr = max(strength.values()) if strength else 1
    maxnb = max(nb.values()) if nb and max(nb.values()) > 0 else 1
    nodes = []
    for g in Gb.nodes():
        score = 0.5*(strength.get(g,0)/maxstr) + 0.25*(deg.get(g,0)/maxdeg) + 0.25*(nb.get(g,0)/maxnb)
        nodes.append({"gene":g, "degree":deg.get(g,0), "strength":strength.get(g,0), "betweenness":nb.get(g,0), "two_order_node_score":score})
    nodes = pd.DataFrame(nodes).sort_values("two_order_node_score", ascending=False)
    h2, c2 = continuous_h(nodes["two_order_node_score"], 20)
    nodes["hub_status"] = ["Hub gene" if s >= c2 else "Candidate" for s in nodes["two_order_node_score"]]
    edges.to_csv(args.out_prefix + "_edges.csv", index=False)
    nodes.to_csv(args.out_prefix + "_nodes.csv", index=False)
    print({"one_order_h": h1, "one_order_cutoff": c1, "two_order_h": h2, "two_order_cutoff": c2})

if __name__ == "__main__":
    main()
