from __future__ import annotations

from functools import lru_cache
from typing import Any


@lru_cache(maxsize=16)
def _xor_translation_tables(key: int) -> tuple[bytes, ...]:
    identity = bytes(range(256))
    key_bytes = int(key).to_bytes(8, "little", signed=False)
    return tuple(
        bytes.maketrans(identity, bytes(value ^ key_byte for value in range(256)))
        for key_byte in key_bytes
    )


def xor_in_place(data: bytearray, key: int, start_offset: int = 0) -> None:
    """Apply the repeating 64-bit KsPkg XOR key using C-level byte translation."""
    if not data:
        return
    tables = _xor_translation_tables(int(key))
    offset = max(0, int(start_offset)) % 8
    for lane in range(8):
        source = data[lane::8]
        if source:
            data[lane::8] = source.translate(tables[(offset + lane) % 8])


def progress_payload(
    *,
    current: int,
    total: int,
    path: str,
    files_written: int,
    directories_created: int,
    bytes_processed: int,
    total_bytes: int,
    current_file_bytes: int,
    current_file_size: int,
    elapsed_seconds: float,
) -> dict[str, Any]:
    processed = max(0, int(bytes_processed))
    byte_total = max(0, int(total_bytes))
    elapsed = max(0.0, float(elapsed_seconds))
    speed = processed / elapsed if processed > 0 and elapsed > 0 else 0.0
    remaining = max(0, byte_total - processed)
    eta = remaining / speed if speed > 0 else 0.0
    if byte_total > 0:
        percent = min(100.0, processed * 100.0 / byte_total)
    else:
        percent = min(100.0, max(0, int(current)) * 100.0 / max(1, int(total)))
    return {
        "current": max(0, int(current)),
        "total": max(0, int(total)),
        "percent": round(percent, 1),
        "path": str(path or ""),
        "filesWritten": max(0, int(files_written)),
        "directoriesCreated": max(0, int(directories_created)),
        "bytesProcessed": processed,
        "totalBytes": byte_total,
        "currentFileBytes": max(0, int(current_file_bytes)),
        "currentFileSize": max(0, int(current_file_size)),
        "bytesPerSecond": round(speed),
        "elapsedSeconds": round(elapsed, 1),
        "etaSeconds": round(eta, 1),
    }
