"""Inspect text structures or BinaryCIF container metadata without editing."""
import argparse
import hashlib
import json
from pathlib import Path

import msgpack
from Bio.PDB import MMCIFParser, PDBParser
from Bio.PDB.MMCIF2Dict import MMCIF2Dict


def inspect(path):
    suffix = path.suffix.lower()
    report = {"file": path.name, "bytes": path.stat().st_size,
              "sha256": hashlib.sha256(path.read_bytes()).hexdigest()}
    if suffix == ".bcif":
        container = msgpack.unpackb(path.read_bytes(), raw=False)
        report["binarycif_version"] = container["version"]
        report["blocks"] = [
            {"header": block["header"],
             "atom_site_tables": [
                 {"rows": category["rowCount"],
                  "columns": [column["name"] for column in category["columns"]]}
                 for category in block["categories"]
                 if category["name"] == "_atom_site"]}
            for block in container["dataBlocks"]]
        return report  # Encoded column values and masks are NOT decoded here.
    if suffix == ".pdb":
        parser = PDBParser(PERMISSIVE=False)
    elif suffix == ".cif":
        parser = MMCIFParser(auth_chains=True, auth_residues=True)
    else:
        raise ValueError("Use an uncompressed .pdb, .cif, or .bcif file")
    structure = parser.get_structure(path.stem, str(path))
    report["models"] = [
            {"parser_model_serial": int(model.serial_num),
             "chain_ids": [chain.id for chain in model],
             "selected_atom_objects": sum(1 for _ in model.get_atoms())}
            for model in structure
        ]
    if suffix == ".cif":
        table = MMCIF2Dict(str(path))
        pairs = sorted(set(zip(table["_atom_site.label_asym_id"],
                               table["_atom_site.auth_asym_id"])))
        report["atom_site_rows"] = len(table["_atom_site.id"])
        report["label_to_auth_chain_pairs"] = pairs
    return report


def main():
    cli = argparse.ArgumentParser(description=__doc__)
    cli.add_argument("files", nargs="+", type=Path)
    args = cli.parse_args()
    try:
        reports = [inspect(path) for path in args.files]
    except Exception as error:
        cli.exit(1, f"Cannot inspect structure: {error}\n")
    print(json.dumps(reports, indent=2))


if __name__ == "__main__":
    main()
