"""
helix_cdc/capsules/crypto_padding.py
====================================

RSA-Style Regenerative Padding Engine

Repurposes RSA padding structures (PKCS1/OAEP-like) for REGENERATIVE
encoding rather than security. The padding adds regulatory regions,
morphogenetic metadata, and growth control fields.

WO#50: Crypto-DNA Regenerative Substrate
"""

import hashlib
import struct
from dataclasses import dataclass
from typing import Dict, Any, Tuple, Optional

# Padding markers (repurposed from crypto)
START_CODON_MARKER = 0x02
STOP_CODON_MARKER = 0x03
REGULATORY_MARKER = 0x10
FIBPI3D_MARKER = 0x20
GROWTH_MARKER = 0x30
EPIGENETIC_MARKER = 0x40
COMPAT_MARKER = 0x50
RESIDUAL_MARKER = 0x60


@dataclass
class RegulatoryRegion:
    """Regulatory region metadata."""
    domain: str = "general-llm"
    safety_class: str = "research"
    blood_type_code: str = "O+"
    rh_positive: bool = True


@dataclass
class FibPi3DOffsets:
    """FibPi3D spatial offsets."""
    x: float = 0.0
    y: float = 0.0
    z: float = 0.0


@dataclass
class GrowthSwitches:
    """Growth control parameters."""
    rate: float = 1.0
    branch_factor: int = 2
    depth_limit: int = 32
    diffusion: float = 0.1


@dataclass
class EpigeneticFlags:
    """Epigenetic modification markers."""
    flags: int = 0
    # Bit 0: methylation
    # Bit 1: acetylation
    # Bit 2: phosphorylation
    # Bit 3: ubiquitination
    # Bits 4-7: reserved
    # Bits 8-31: extension flags


@dataclass
class PaddingConfig:
    """Full padding configuration."""
    regulatory: RegulatoryRegion = None
    fibpi3d: FibPi3DOffsets = None
    growth: GrowthSwitches = None
    epigenetic: EpigeneticFlags = None
    compat_class: str = "M7B-Q4KM-v1"
    residual_mode: int = 0  # 0 = v0 (XOR), 1 = v1 (structured)

    def __post_init__(self):
        if self.regulatory is None:
            self.regulatory = RegulatoryRegion()
        if self.fibpi3d is None:
            self.fibpi3d = FibPi3DOffsets()
        if self.growth is None:
            self.growth = GrowthSwitches()
        if self.epigenetic is None:
            self.epigenetic = EpigeneticFlags()


def _encode_regulatory(reg: RegulatoryRegion) -> bytes:
    """Encode regulatory region to 8 bytes."""
    # Domain: 2 bytes (hash prefix)
    domain_hash = hashlib.sha256(reg.domain.encode()).digest()[:2]

    # Safety class: 1 byte
    safety_map = {'toy': 0, 'research': 1, 'clinical': 2, 'critical': 3}
    safety_byte = safety_map.get(reg.safety_class, 1)

    # Blood type: 2 bytes
    blood_hash = hashlib.sha256(reg.blood_type_code.encode()).digest()[:2]

    # Rh flag: 1 byte
    rh_byte = 0x01 if reg.rh_positive else 0x00

    # Reserved: 2 bytes
    reserved = b'\x00\x00'

    return domain_hash + bytes([safety_byte]) + blood_hash + bytes([rh_byte]) + reserved


def _encode_fibpi3d(offsets: FibPi3DOffsets) -> bytes:
    """Encode FibPi3D offsets to 12 bytes (3 x float32)."""
    return struct.pack('>fff', offsets.x, offsets.y, offsets.z)


def _encode_growth(growth: GrowthSwitches) -> bytes:
    """Encode growth switches to 4 bytes."""
    # Rate: 1 byte (0-255 maps to 0.0-2.55)
    rate_byte = min(255, int(growth.rate * 100))

    # Branch factor: 1 byte
    branch_byte = min(255, growth.branch_factor)

    # Depth limit: 1 byte
    depth_byte = min(255, growth.depth_limit)

    # Diffusion: 1 byte (0-255 maps to 0.0-1.0)
    diff_byte = min(255, int(growth.diffusion * 255))

    return bytes([rate_byte, branch_byte, depth_byte, diff_byte])


def _encode_epigenetic(epi: EpigeneticFlags) -> bytes:
    """Encode epigenetic flags to 4 bytes."""
    return struct.pack('>I', epi.flags)


def _encode_compat(compat_class: str) -> bytes:
    """Encode compatibility class to 8 bytes (hash prefix)."""
    return hashlib.sha256(compat_class.encode()).digest()[:8]


def _encode_residual(mode: int) -> bytes:
    """Encode residual hooks to 4 bytes."""
    # Mode: 1 byte (0=v0 XOR, 1=v1 structured)
    # Reserved: 3 bytes
    return bytes([mode, 0, 0, 0])


def pad_start_codon() -> bytes:
    """Generate start codon marker."""
    return bytes([START_CODON_MARKER])


def pad_stop_codon() -> bytes:
    """Generate stop codon marker."""
    return bytes([STOP_CODON_MARKER])


def pad_regulatory_region(reg: RegulatoryRegion = None) -> bytes:
    """Generate regulatory region padding."""
    if reg is None:
        reg = RegulatoryRegion()
    return bytes([REGULATORY_MARKER]) + _encode_regulatory(reg)


def pad_fibpi3d_offsets(offsets: FibPi3DOffsets = None) -> bytes:
    """Generate FibPi3D offset padding."""
    if offsets is None:
        offsets = FibPi3DOffsets()
    return bytes([FIBPI3D_MARKER]) + _encode_fibpi3d(offsets)


def pad_growth_switches(growth: GrowthSwitches = None) -> bytes:
    """Generate growth switch padding."""
    if growth is None:
        growth = GrowthSwitches()
    return bytes([GROWTH_MARKER]) + _encode_growth(growth)


def pad_epigenetic_flags(epi: EpigeneticFlags = None) -> bytes:
    """Generate epigenetic flag padding."""
    if epi is None:
        epi = EpigeneticFlags()
    return bytes([EPIGENETIC_MARKER]) + _encode_epigenetic(epi)


def pad_compat_class(compat_class: str = "M7B-Q4KM-v1") -> bytes:
    """Generate compatibility class padding."""
    return bytes([COMPAT_MARKER]) + _encode_compat(compat_class)


def pad_residual_hooks(mode: int = 0) -> bytes:
    """Generate residual hook padding."""
    return bytes([RESIDUAL_MARKER]) + _encode_residual(mode)


def build_full_padding(config: PaddingConfig = None) -> bytes:
    """
    Build complete padding structure.

    Layout:
        [START_CODON]           1 byte
        [REGULATORY_MARKER]     1 byte
        [regulatory_data]       8 bytes
        [FIBPI3D_MARKER]        1 byte
        [fibpi3d_data]          12 bytes
        [GROWTH_MARKER]         1 byte
        [growth_data]           4 bytes
        [EPIGENETIC_MARKER]     1 byte
        [epigenetic_data]       4 bytes
        [COMPAT_MARKER]         1 byte
        [compat_data]           8 bytes
        [RESIDUAL_MARKER]       1 byte
        [residual_data]         4 bytes
        ---
        Total header: 47 bytes
    """
    if config is None:
        config = PaddingConfig()

    padding = b''
    padding += pad_start_codon()
    padding += pad_regulatory_region(config.regulatory)
    padding += pad_fibpi3d_offsets(config.fibpi3d)
    padding += pad_growth_switches(config.growth)
    padding += pad_epigenetic_flags(config.epigenetic)
    padding += pad_compat_class(config.compat_class)
    padding += pad_residual_hooks(config.residual_mode)

    return padding


def apply_crypto_padding(n: int, config: PaddingConfig = None) -> int:
    """
    Apply crypto-style padding to genome integer.

    The padding is prepended to the genome, creating a larger
    integer with regulatory structure.

    Args:
        n: Original genome bigint
        config: Padding configuration

    Returns:
        Padded genome bigint N'
    """
    padding = build_full_padding(config)

    # Convert genome to bytes
    genome_len = (n.bit_length() + 7) // 8
    if genome_len == 0:
        genome_len = 1
    genome_bytes = n.to_bytes(genome_len, byteorder='big')

    # Combine: padding + genome + stop codon
    full_bytes = padding + genome_bytes + pad_stop_codon()

    # Convert back to bigint
    return int.from_bytes(full_bytes, byteorder='big')


def parse_padded_genome(n_padded: int) -> Tuple[int, Dict[str, Any]]:
    """
    Parse a padded genome back into original genome + metadata.

    Args:
        n_padded: Padded genome bigint

    Returns:
        (original_genome, metadata_dict)
    """
    # Convert to bytes
    byte_len = (n_padded.bit_length() + 7) // 8
    data = n_padded.to_bytes(byte_len, byteorder='big')

    metadata = {}
    pos = 0

    # Check start codon
    if data[pos] != START_CODON_MARKER:
        raise ValueError("Missing start codon marker")
    pos += 1

    # Parse sections
    while pos < len(data) - 1:  # -1 for stop codon
        marker = data[pos]
        pos += 1

        if marker == REGULATORY_MARKER:
            metadata['regulatory'] = data[pos:pos+8]
            pos += 8
        elif marker == FIBPI3D_MARKER:
            x, y, z = struct.unpack('>fff', data[pos:pos+12])
            metadata['fibpi3d'] = {'x': x, 'y': y, 'z': z}
            pos += 12
        elif marker == GROWTH_MARKER:
            metadata['growth'] = {
                'rate': data[pos] / 100.0,
                'branch_factor': data[pos+1],
                'depth_limit': data[pos+2],
                'diffusion': data[pos+3] / 255.0,
            }
            pos += 4
        elif marker == EPIGENETIC_MARKER:
            metadata['epigenetic'] = struct.unpack('>I', data[pos:pos+4])[0]
            pos += 4
        elif marker == COMPAT_MARKER:
            metadata['compat_hash'] = data[pos:pos+8].hex()
            pos += 8
        elif marker == RESIDUAL_MARKER:
            metadata['residual_mode'] = data[pos]
            pos += 4
        elif marker == STOP_CODON_MARKER:
            # Found stop codon, genome is between current pos and stop
            break
        else:
            # Unknown marker - this is genome data
            # Backtrack and extract genome
            pos -= 1
            break

    # Find stop codon
    stop_pos = data.rfind(bytes([STOP_CODON_MARKER]))
    if stop_pos == -1:
        raise ValueError("Missing stop codon marker")

    # Extract genome
    genome_bytes = data[pos:stop_pos]
    genome = int.from_bytes(genome_bytes, byteorder='big')

    return genome, metadata


def derive_offsets_from_seed(seed_bytes: bytes) -> FibPi3DOffsets:
    """
    Derive FibPi3D offsets deterministically from seed.
    """
    h = hashlib.sha256(b'fibpi3d:' + seed_bytes).digest()

    x = struct.unpack('>f', h[0:4])[0] % 1.0
    y = struct.unpack('>f', h[4:8])[0] % 1.0
    z = struct.unpack('>f', h[8:12])[0] % 1.0

    return FibPi3DOffsets(x=x, y=y, z=z)
