#!/usr/bin/env python3
"""Copy a Freqtrade backtest zip while removing embedded config members."""

from __future__ import annotations

import argparse
import hashlib
import json
import zipfile
from pathlib import Path


def sha256_file(path: Path, chunk_size: int = 1024 * 1024) -> str:
    digest = hashlib.sha256()
    with path.open("rb") as handle:
        for chunk in iter(lambda: handle.read(chunk_size), b""):
            digest.update(chunk)
    return digest.hexdigest()


def is_sensitive_member(name: str) -> bool:
    return name.endswith("_config.json")


def sanitize_archive(source: Path, destination: Path) -> dict[str, object]:
    if source.resolve() == destination.resolve():
        raise ValueError("source and destination must differ")
    destination.parent.mkdir(parents=True, exist_ok=True)
    removed: list[str] = []
    retained: list[str] = []
    with zipfile.ZipFile(source) as reader, zipfile.ZipFile(
        destination, "w", compression=zipfile.ZIP_DEFLATED
    ) as writer:
        for info in reader.infolist():
            if is_sensitive_member(info.filename):
                removed.append(info.filename)
                continue
            writer.writestr(info, reader.read(info.filename))
            retained.append(info.filename)

    with zipfile.ZipFile(destination) as verifier:
        unsafe = [name for name in verifier.namelist() if is_sensitive_member(name)]
        if unsafe:
            raise RuntimeError(f"sanitized archive still contains config: {unsafe}")
    if not removed:
        raise ValueError("source archive contained no embedded config member")
    return {
        "source": str(source),
        "source_sha256": sha256_file(source),
        "destination": str(destination),
        "destination_sha256": sha256_file(destination),
        "removed_members": removed,
        "retained_members": retained,
    }


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("source", type=Path)
    parser.add_argument("destination", type=Path)
    parser.add_argument("--manifest", type=Path)
    args = parser.parse_args()
    result = sanitize_archive(args.source, args.destination)
    if args.manifest:
        args.manifest.parent.mkdir(parents=True, exist_ok=True)
        args.manifest.write_text(
            json.dumps(result, ensure_ascii=False, indent=2, sort_keys=True) + "\n",
            encoding="utf-8",
        )
    print(json.dumps(result, ensure_ascii=False, sort_keys=True))
    return 0


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