#!/usr/bin/env python3
"""Verify a QORLYNT NDJSON export and unpack it without a QORLYNT installation.

Usage: python3 unpack-data-export.py qorlynt-export.ndjson NEW_DIRECTORY
Uses only Python's standard library. Never executes archive content or imports it
into a live tenant. The destination must not exist; failures leave no final result.
"""
import base64
import hashlib
import json
import os
from pathlib import Path
import re
import shutil
import sys
import tempfile


def unpack(source, destination):
    destination = Path(destination).absolute()
    if destination.exists():
        raise ValueError("Destination already exists")
    temp = Path(tempfile.mkdtemp(prefix=".qorlynt-export-", dir=destination.parent))
    digest, counts, files = hashlib.sha256(), {}, {}
    manifest = complete = None
    references = set()
    try:
        (temp / "records").mkdir()
        (temp / "files").mkdir()
        with open(source, "rb") as stream:
            while True:
                line = stream.readline(64 * 1024 * 1024 + 1)
                if not line:
                    break
                if complete or len(line) > 64 * 1024 * 1024 or not line.endswith(b"\n"):
                    raise ValueError("Invalid framing or trailing data")
                item = json.loads(line)
                kind = item.get("type")
                if kind == "complete":
                    if not manifest or item.get("schemaVersion") != "qorlynt-export-1":
                        raise ValueError("Missing manifest or unsupported version")
                    if item.get("sha256") != digest.hexdigest() or item.get("counts") != counts or item.get("files") != len(files):
                        raise ValueError("Incomplete or altered export")
                    complete = item
                    continue
                digest.update(line)
                if kind == "manifest":
                    if manifest or item.get("schemaVersion") != "qorlynt-export-1":
                        raise ValueError("Duplicate manifest or unsupported version")
                    manifest = item
                    for dataset in item["datasets"]:
                        name = dataset["name"]
                        if not re.fullmatch(r"[a-z][a-z0-9_]*", name) or name in counts:
                            raise ValueError("Invalid or duplicate dataset")
                        counts[name] = 0
                        (temp / "records" / (name + ".jsonl")).touch(mode=0o600)
                    (temp / "manifest.json").write_text(json.dumps(item, ensure_ascii=False, indent=2), encoding="utf-8")
                elif not manifest:
                    raise ValueError("Manifest must be first")
                elif kind == "record":
                    name = item["dataset"]
                    if name not in counts or not isinstance(item["data"], dict):
                        raise ValueError("Unknown dataset or invalid record")
                    with (temp / "records" / (name + ".jsonl")).open("a", encoding="utf-8") as output:
                        output.write(json.dumps(item["data"], ensure_ascii=False) + "\n")
                    if name in ("object_payloads", "customer_media") and "file" in item["data"]:
                        references.add(item["data"]["file"])
                    counts[name] += 1
                elif kind == "file":
                    key = item["key"]
                    if not isinstance(key, str) or key in files:
                        raise ValueError("Invalid or duplicate file key")
                    data = base64.b64decode(item["base64"], validate=True)
                    if len(data) != item["bytes"] or hashlib.sha256(data).hexdigest() != item["sha256"]:
                        raise ValueError("File checksum mismatch")
                    # User-controlled IDs and filenames are never filesystem paths.
                    name = hashlib.sha256(key.encode()).hexdigest() + ".bin"
                    target = temp / "files" / name
                    with target.open("xb") as output:
                        output.write(data)
                    os.chmod(target, 0o600)
                    files[key] = {"path": "files/" + name, "mime": item["mime"], "sha256": item["sha256"], "bytes": item["bytes"]}
                else:
                    raise ValueError("Unknown record type")
        if not references.issubset(files):
            raise ValueError("Missing referenced file")
        if not complete:
            raise ValueError("Export has no completion receipt; download it again")
        (temp / "files.json").write_text(json.dumps(files, ensure_ascii=False, indent=2), encoding="utf-8")
        (temp / "receipt.json").write_text(json.dumps(complete, indent=2), encoding="utf-8")
        if destination.exists():
            raise ValueError("Destination appeared during verification")
        temp.rename(destination)
        return {"records": sum(counts.values()), "files": len(files), "datasets": len(counts)}
    except BaseException:
        shutil.rmtree(temp)
        raise


if __name__ == "__main__":
    if len(sys.argv) != 3:
        raise SystemExit(__doc__)
    try:
        print(json.dumps(unpack(sys.argv[1], sys.argv[2])))
    except (ValueError, KeyError, TypeError, OSError) as error:
        raise SystemExit("Export verification failed: " + str(error)) from None
