#!/usr/bin/env python3
"""Parse _ExtensionsInfo._ExtensionZippedInfo blobs.

Observed structure starts with a 4-byte marker, followed by a 20-byte SHA1 key
that points to a ConfigCAS file. The rest contains small extension metadata,
including a UTF-16LE serialized text fragment.
"""

from __future__ import annotations

import argparse
import json
from pathlib import Path
from typing import Any

from inspect_1c_sql_files import GUID_RE


def extract_utf16le_fragment(data: bytes) -> str:
    starts = [pos for pos in (data.find(b"{\x00"), data.find(b'"\x00#\x00"\x00')) if pos >= 0]
    if not starts:
        return ""
    start = min(starts)
    fragment = data[start:]
    if len(fragment) % 2:
        fragment = fragment[:-1]
    try:
        return fragment.decode("utf-16-le", errors="ignore").strip("\x00")
    except UnicodeError:
        return ""


def parse_blob(path: Path, cas_dir: Path | None) -> dict[str, Any]:
    data = path.read_bytes()
    root_key = data[4:24].hex() if len(data) >= 24 else ""
    text = extract_utf16le_fragment(data)
    cas_path = cas_dir / root_key if cas_dir and root_key else None
    return {
        "file_name": path.name,
        "path": str(path),
        "bytes": len(data),
        "marker_hex": data[:4].hex(),
        "root_cas_key": root_key,
        "root_cas_exists": bool(cas_path and cas_path.is_file()),
        "root_cas_path": str(cas_path) if cas_path and cas_path.is_file() else None,
        "text_fragment": text,
        "guids": sorted(set(match.lower() for match in GUID_RE.findall(text))),
    }


def main() -> int:
    parser = argparse.ArgumentParser(description="Parse exported _ExtensionZippedInfo blobs.")
    parser.add_argument("input", type=Path, help="A blob file or directory with *_ExtensionZippedInfo.bin files.")
    parser.add_argument("--cas-dir", type=Path)
    parser.add_argument("--output", type=Path, required=True)
    args = parser.parse_args()

    files = [args.input] if args.input.is_file() else sorted(args.input.glob("*ExtensionZippedInfo.bin"))
    items = [parse_blob(path, args.cas_dir) for path in files]
    report = {
        "schema": "onec_extension_zipped_info.v1",
        "input": str(args.input),
        "cas_dir": str(args.cas_dir) if args.cas_dir else None,
        "file_count": len(items),
        "root_cas_found_count": sum(1 for item in items if item["root_cas_exists"]),
        "items": items,
    }
    args.output.parent.mkdir(parents=True, exist_ok=True)
    args.output.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
    print(
        json.dumps(
            {
                "output": str(args.output),
                "files": len(items),
                "root_cas_found": report["root_cas_found_count"],
            },
            ensure_ascii=False,
        )
    )
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
