"""
Formal spec formats for prompt2bin domains.

This is the structured intermediate representation between
natural language intent and verified code generation.
An AI generates these specs; a human never writes them directly.

Domains:
  - Arena allocator (ArenaSpec)
  - Ring buffer / SPSC queue (RingBufferSpec)
"""

from dataclasses import dataclass, field
from enum import Enum
from typing import Optional


class ThreadSafety(Enum):
    SINGLE_THREADED = "single_threaded"
    THREAD_LOCAL = "thread_local"
    LOCK_FREE = "lock_free"


class AllocStrategy(Enum):
    BUMP = "bump"           # Linear bump pointer, O(1) alloc
    POOL = "pool"           # Fixed-size block pool
    FREELIST = "freelist"   # Free list with coalescing


class GrowthPolicy(Enum):
    FIXED = "fixed"         # Single arena, no growth
    CHAIN = "chain"         # Chain new arenas when full
    DOUBLE = "double"       # Double arena size on growth


@dataclass
class AlignmentSpec:
    min_align: int = 8          # Minimum alignment in bytes
    max_align: int = 64         # Maximum alignment supported
    natural_align: bool = True  # Align to type's natural alignment


@dataclass
class MemoryBounds:
    page_size: int = 4096           # Arena page size in bytes
    max_pages: int = 1              # Maximum number of pages
    max_alloc_size: int = 0         # Max single allocation (0 = page_size - header)
    header_size: int = 16           # Per-arena metadata overhead

    @property
    def total_capacity(self) -> int:
        return self.page_size * self.max_pages

    @property
    def usable_capacity(self) -> int:
        return self.total_capacity - (self.header_size * self.max_pages)

    @property
    def effective_max_alloc(self) -> int:
        if self.max_alloc_size > 0:
            return self.max_alloc_size
        return self.page_size - self.header_size


@dataclass
class SafetyInvariants:
    no_overflow: bool = True            # Bump pointer never exceeds arena bounds
    aligned_allocs: bool = True         # All returned pointers are aligned
    bounded_memory: bool = True         # Total memory usage is provably bounded
    no_use_after_reset: bool = False    # Prevent use-after-free (requires generation tracking)
    zero_on_alloc: bool = False         # Zero memory on allocation
    zero_on_reset: bool = False         # Zero memory on reset (security)


@dataclass
class PerformanceConstraints:
    alloc_time_ns: Optional[int] = None     # Max allocation time in ns
    reset_time_ns: Optional[int] = None     # Max reset time in ns
    cache_line_size: int = 64               # Target cache line size


@dataclass
class ArenaSpec:
    """
    Complete formal specification for an arena allocator.

    Generated by AI from natural language intent.
    Verified by Z3 before code generation.
    """
    name: str = "arena"

    strategy: AllocStrategy = AllocStrategy.BUMP
    growth: GrowthPolicy = GrowthPolicy.FIXED
    thread_safety: ThreadSafety = ThreadSafety.SINGLE_THREADED

    memory: MemoryBounds = field(default_factory=MemoryBounds)
    alignment: AlignmentSpec = field(default_factory=AlignmentSpec)
    safety: SafetyInvariants = field(default_factory=SafetyInvariants)
    performance: PerformanceConstraints = field(default_factory=PerformanceConstraints)

    def describe(self) -> str:
        """Human-readable summary of the spec."""
        lines = [
            f"Arena Allocator Spec: {self.name}",
            f"  Strategy: {self.strategy.value}",
            f"  Growth: {self.growth.value}",
            f"  Threading: {self.thread_safety.value}",
            f"  Page size: {self.memory.page_size} bytes",
            f"  Max pages: {self.memory.max_pages}",
            f"  Total capacity: {self.memory.total_capacity} bytes",
            f"  Usable capacity: {self.memory.usable_capacity} bytes",
            f"  Max single alloc: {self.memory.effective_max_alloc} bytes",
            f"  Alignment: {self.alignment.min_align}-{self.alignment.max_align} bytes",
            f"  Safety: " + ", ".join(
                k for k, v in vars(self.safety).items() if v
            ),
        ]
        return "\n".join(lines)


# ── Ring Buffer Domain ──


class RingBufferMode(Enum):
    SPSC = "spsc"       # Single producer, single consumer (fastest)
    MPSC = "mpsc"       # Multiple producers, single consumer
    SPMC = "spmc"       # Single producer, multiple consumers
    MPMC = "mpmc"       # Multiple producers, multiple consumers


class ElementType(Enum):
    BYTES = "bytes"     # Raw byte buffer (user casts)
    FIXED = "fixed"     # Fixed-size elements


@dataclass
class RingBufferSpec:
    """
    Complete formal specification for a ring buffer / circular queue.

    Generated by AI from natural language intent.
    Verified by Z3 before code generation.
    """
    name: str = "ringbuf"

    mode: RingBufferMode = RingBufferMode.SPSC
    element_type: ElementType = ElementType.FIXED
    element_size: int = 8           # Size of each element in bytes
    capacity: int = 1024            # Number of elements (MUST be power of two)
    cache_line_pad: bool = True     # Pad head/tail to separate cache lines
    blocking: bool = False          # Block on full/empty vs return error

    # Safety
    bounded_memory: bool = True     # Total memory provably bounded
    no_data_loss: bool = True       # Writes to full buffer return error (not overwrite)
    no_torn_reads: bool = True      # Reads are always complete elements

    @property
    def buffer_size_bytes(self) -> int:
        return self.capacity * self.element_size

    @property
    def total_memory_bytes(self) -> int:
        """Total including struct overhead."""
        overhead = 128 if self.cache_line_pad else 16  # head + tail + padding
        return self.buffer_size_bytes + overhead

    @property
    def index_mask(self) -> int:
        """Bitmask for fast modulo (capacity must be power of two)."""
        return self.capacity - 1

    def describe(self) -> str:
        """Human-readable summary of the spec."""
        lines = [
            f"Ring Buffer Spec: {self.name}",
            f"  Mode: {self.mode.value}",
            f"  Element: {self.element_size} bytes x {self.capacity} slots",
            f"  Buffer size: {self.buffer_size_bytes} bytes",
            f"  Total memory: {self.total_memory_bytes} bytes",
            f"  Index mask: 0x{self.index_mask:X}",
            f"  Cache line padding: {self.cache_line_pad}",
            f"  Blocking: {self.blocking}",
            f"  Safety: " + ", ".join(
                k for k, v in {
                    "bounded_memory": self.bounded_memory,
                    "no_data_loss": self.no_data_loss,
                    "no_torn_reads": self.no_torn_reads,
                }.items() if v
            ),
        ]
        return "\n".join(lines)
