#!/usr/bin/env python3
import lzma
import sys


def open_text(path):
    if path.endswith(".xz"):
        return lzma.open(path, "rt", encoding="ascii", errors="ignore")
    return open(path, "rt", encoding="ascii", errors="ignore")


def read_model(path):
    assign = {}
    saw_sat = False
    with open(path, "rt", encoding="ascii", errors="ignore") as f:
        for line in f:
            if line.startswith("s "):
                saw_sat = "SATISFIABLE" in line and "UNSATISFIABLE" not in line
            if not line.startswith("v"):
                continue
            for tok in line.split()[1:]:
                lit = int(tok)
                if lit == 0:
                    continue
                v = abs(lit)
                val = lit > 0
                old = assign.get(v)
                if old is not None and old != val:
                    raise SystemExit(f"conflicting assignment for variable {v}")
                assign[v] = val
    if not saw_sat:
        raise SystemExit("model file does not contain s SATISFIABLE")
    return assign


def check(cnf_path, model_path):
    assign = read_model(model_path)
    nvars = nclauses = 0
    clauses = bad = 0
    with open_text(cnf_path) as f:
        lits = []
        for line in f:
            if not line or line.startswith("c"):
                continue
            if line.startswith("p"):
                parts = line.split()
                nvars = int(parts[2])
                nclauses = int(parts[3])
                continue
            for tok in line.split():
                lit = int(tok)
                if lit == 0:
                    clauses += 1
                    sat = False
                    for l in lits:
                        val = assign.get(abs(l))
                        if val is not None and ((l > 0) == val):
                            sat = True
                            break
                    if not sat:
                        bad += 1
                        if bad <= 5:
                            print(f"unsatisfied clause {clauses}: {' '.join(map(str, lits))}")
                    lits = []
                else:
                    lits.append(lit)
    if clauses != nclauses:
        raise SystemExit(f"clause count mismatch: saw {clauses}, header {nclauses}")
    if bad:
        raise SystemExit(f"INVALID: {bad} unsatisfied clauses under {len(assign)} assigned variables")
    print(f"VALID: clauses={clauses} assigned={len(assign)} vars={nvars}")


if __name__ == "__main__":
    if len(sys.argv) != 3:
        raise SystemExit("usage: check_model.py formula.cnf[.xz] solver.out")
    check(sys.argv[1], sys.argv[2])
