"""
helix_cdc/capsules/instance_residual.py
=======================================

v0 Instance Residual Codec (Naive XOR Diff)

This is a PROVING SCAFFOLD, not the final compressed format.

The goal is to establish a reversible, testable pattern for exact
instance regeneration (clone mode).

v0 residuals are naive XOR:
    baseline ^ regen = residual
    regen = baseline ^ residual

This is a 1:1 sized residual (no compression).

TODO:
    - Replace XOR residual with structured residual (tensor-level diffs)
    - Entropy-code the residual for compression
    - Integrate with FibPi3D/CDC so residuals are computed in compressed domain
    - Per-layer or per-tensor residuals for selective patching
"""

import hashlib
from pathlib import Path
from typing import Tuple, Optional


def compute_xor_residual(
    baseline_path: Path,
    regen_path: Path,
    out_path: Path,
) -> str:
    """
    v0 instance residual: byte-wise XOR of baseline GGUF and regenerated GGUF.

    This is a naive, 1:1-sized residual that is fully reversible:
        baseline ^ regen = residual
        regen = baseline ^ residual

    This is a proving scaffold, NOT the final compressed format.

    Args:
        baseline_path: Path to baseline (vendor/original) GGUF
        regen_path: Path to regenerated GGUF
        out_path: Path to write residual bytes

    Returns:
        SHA256 of the residual bytes as hex string

    Raises:
        ValueError: If file lengths don't match
        FileNotFoundError: If input files don't exist
    """
    baseline_path = Path(baseline_path)
    regen_path = Path(regen_path)
    out_path = Path(out_path)

    if not baseline_path.exists():
        raise FileNotFoundError(f"Baseline not found: {baseline_path}")
    if not regen_path.exists():
        raise FileNotFoundError(f"Regen not found: {regen_path}")

    baseline_bytes = baseline_path.read_bytes()
    regen_bytes = regen_path.read_bytes()

    if len(baseline_bytes) != len(regen_bytes):
        raise ValueError(
            f"Length mismatch: baseline={len(baseline_bytes):,}, "
            f"regen={len(regen_bytes):,}"
        )

    # XOR byte by byte
    residual = bytes(b ^ r for b, r in zip(baseline_bytes, regen_bytes))

    # Write to output
    out_path.parent.mkdir(parents=True, exist_ok=True)
    out_path.write_bytes(residual)

    # Compute SHA256
    h = hashlib.sha256(residual).hexdigest()

    return h


def reconstruct_regen_from_baseline_and_residual(
    baseline_path: Path,
    residual_path: Path,
    out_path: Path,
) -> str:
    """
    Rebuild regen GGUF from baseline GGUF and stored residual.

    This is the inverse of compute_xor_residual:
        regen = baseline ^ residual

    Args:
        baseline_path: Path to baseline (vendor/original) GGUF
        residual_path: Path to residual bytes
        out_path: Path to write reconstructed GGUF

    Returns:
        SHA256 of the reconstructed GGUF as hex string

    Raises:
        ValueError: If file lengths don't match
        FileNotFoundError: If input files don't exist
    """
    baseline_path = Path(baseline_path)
    residual_path = Path(residual_path)
    out_path = Path(out_path)

    if not baseline_path.exists():
        raise FileNotFoundError(f"Baseline not found: {baseline_path}")
    if not residual_path.exists():
        raise FileNotFoundError(f"Residual not found: {residual_path}")

    baseline_bytes = baseline_path.read_bytes()
    residual_bytes = residual_path.read_bytes()

    if len(baseline_bytes) != len(residual_bytes):
        raise ValueError(
            f"Length mismatch: baseline={len(baseline_bytes):,}, "
            f"residual={len(residual_bytes):,}"
        )

    # XOR to reconstruct
    regen_bytes = bytes(b ^ d for b, d in zip(baseline_bytes, residual_bytes))

    # Write to output
    out_path.parent.mkdir(parents=True, exist_ok=True)
    out_path.write_bytes(regen_bytes)

    # Compute SHA256
    h = hashlib.sha256(regen_bytes).hexdigest()

    return h


def compute_file_hash(path: Path) -> str:
    """Compute SHA256 of a file."""
    return hashlib.sha256(Path(path).read_bytes()).hexdigest()


def verify_clone_mode_roundtrip(
    baseline_path: Path,
    regen_path: Path,
    residual_path: Path,
    reconstructed_path: Path,
) -> Tuple[bool, dict]:
    """
    Verify that clone mode roundtrip works correctly.

    Steps:
        1. Compute residual = baseline ^ regen
        2. Reconstruct = baseline ^ residual
        3. Verify reconstruct == regen (byte-for-byte)

    Args:
        baseline_path: Path to baseline GGUF
        regen_path: Path to regenerated GGUF
        residual_path: Path to write residual (temp)
        reconstructed_path: Path to write reconstructed (temp)

    Returns:
        (success, details) where details has hashes and verification info
    """
    baseline_path = Path(baseline_path)
    regen_path = Path(regen_path)
    residual_path = Path(residual_path)
    reconstructed_path = Path(reconstructed_path)

    # Step 1: Compute residual
    residual_hash = compute_xor_residual(baseline_path, regen_path, residual_path)

    # Step 2: Reconstruct
    reconstructed_hash = reconstruct_regen_from_baseline_and_residual(
        baseline_path, residual_path, reconstructed_path
    )

    # Step 3: Verify
    original_regen_hash = compute_file_hash(regen_path)

    success = reconstructed_hash == original_regen_hash

    details = {
        "baseline_path": str(baseline_path),
        "regen_path": str(regen_path),
        "residual_path": str(residual_path),
        "reconstructed_path": str(reconstructed_path),
        "baseline_hash": compute_file_hash(baseline_path),
        "original_regen_hash": original_regen_hash,
        "residual_hash": residual_hash,
        "reconstructed_hash": reconstructed_hash,
        "residual_size_bytes": residual_path.stat().st_size,
        "success": success,
        "codec": "xor_v0",
    }

    return success, details
