#!/usr/bin/env python3
import argparse
import collections
import json
import lzma
import os
import re
import sys


def clauses(path):
    opener = lzma.open if path.endswith(".xz") else open
    mode = "rt"
    with opener(path, mode, encoding="ascii", errors="replace") as f:
        nvars = nclauses = None
        cur = []
        for line in f:
            if not line or line[0] == "c":
                continue
            if line[0] == "p":
                parts = line.split()
                nvars, nclauses = int(parts[2]), int(parts[3])
                continue
            for tok in line.split():
                lit = int(tok)
                if lit == 0:
                    yield nvars, nclauses, cur
                    cur = []
                else:
                    cur.append(lit)


def profile(path, first_n=200000):
    header = None
    size_hist = collections.Counter()
    pos = neg = 0
    degree = collections.Counter()
    first_clauses = []
    pair_hist = collections.Counter()
    triples = []
    count = 0
    max_var_seen = 0
    for nvars, nclauses, cl in clauses(path):
        if header is None:
            header = (nvars, nclauses)
        count += 1
        if len(first_clauses) < 25:
            first_clauses.append(cl[:])
        size_hist[len(cl)] += 1
        if len(cl) == 2:
            a, b = sorted(abs(x) for x in cl)
            pair_hist[(a, b, tuple(1 if x > 0 else -1 for x in cl))] += 1
        if len(cl) == 3 and len(triples) < 20:
            triples.append(cl[:])
        for lit in cl:
            max_var_seen = max(max_var_seen, abs(lit))
            if lit > 0:
                pos += 1
            else:
                neg += 1
            degree[abs(lit)] += 1
        if count >= first_n and first_n:
            # Header clause count is enough; stop early for large global stats.
            pass
    nvars, nclauses = header
    deg_values = sorted(degree.values())
    q = {}
    if deg_values:
        for pct in [0, 1, 5, 25, 50, 75, 95, 99, 100]:
            idx = min(len(deg_values) - 1, int((len(deg_values) - 1) * pct / 100))
            q[str(pct)] = deg_values[idx]
    return {
        "file": os.path.basename(path),
        "nvars": nvars,
        "nclauses": nclauses,
        "size_hist": dict(sorted(size_hist.items())),
        "pos": pos,
        "neg": neg,
        "degree_quantiles": q,
        "first_clauses": first_clauses,
        "first_triples": triples,
        "max_var_seen": max_var_seen,
    }


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("paths", nargs="+")
    ap.add_argument("--jsonl", action="store_true")
    args = ap.parse_args()
    for p in args.paths:
        out = profile(p, first_n=0)
        if args.jsonl:
            print(json.dumps(out, sort_keys=True))
        else:
            print(json.dumps(out, indent=2, sort_keys=True))


if __name__ == "__main__":
    main()
