# hardware specific
def _hw_guidance(hw: str) -> str:
    lines = []
    if "avx2" in hw:
        lines.append("- AVX2 (256-bit): 8 floats or 4 doubles per cycle; inner loops over contiguous float arrays auto-vectorize with -O3 -march=native if no aliasing and no data dependencies across iterations.")
    elif "avx" in hw:
        lines.append("- AVX (256-bit): 8 floats per cycle; same conditions as AVX2 but no integer gather/scatter.")
    if "fma" in hw:
        lines.append("- FMA: fused multiply-add available; compiler uses it automatically with -ffp-contract=fast.")
    if "cpu_count" in hw:
        try:
            n = int(hw.split("cpu_count=")[1].split()[0])
            if n >= 4:
                lines.append(f"- {n} logical cores: OpenMP outer-loop parallelism scales well; use #pragma omp parallel for with private accumulators and reduction clauses.")
        except Exception:
            pass
    lines += [
        "- Cache: L1 ~32KB, L2 ~256KB per core; data accessed in a tight inner loop should fit in L1; struct-of-arrays (SoA) layouts keep one field contiguous, improving cache line utilization and enabling SIMD.",
        "- Memory layout: AoS (array of structs) with mixed fields causes strided loads that defeat vectorization; SoA (separate arrays per field) allows contiguous loads.",
    ]
    return "\n".join(lines) if lines else ""


# general strategies
_OPTIMIZATION_TAXONOMY = """
General C performance optimization strategies — consider each category in order:

MEMORY LAYOUT
  soa_layout         : Convert AoS (struct per element) to SoA (one array per field). Enables SIMD, improves cache locality.
  align_arrays        : Add __attribute__((aligned(32))) to hot arrays so AVX2 can use aligned loads.
  pad_struct          : Pad struct fields to avoid false sharing or cache-line splits on hot arrays.

ALLOCATION
  static_buffers      : Replace per-call malloc/calloc/free with static or stack-allocated arrays; eliminates allocator overhead in hot loops.
  reuse_scratch       : Allocate scratch buffers once outside the loop; zero with memset each iteration instead of calloc.

ALIASING & COMPILER HINTS
  restrict_pointers   : Declare pointer parameters as restrict so the compiler assumes no aliasing; enables vectorization of loops that would otherwise need alias checks.
  const_hoisting      : Hoist loop-invariant values into const locals before the inner loop; prevents redundant reloads.

ARITHMETIC
  replace_pow_with_mul: Replace pow(x, integer) with explicit multiplications; pow is a general transcendental, integer cases are trivially faster.
  strength_reduction  : Replace division in inner loops with a reciprocal computed once outside the loop (if divisor is loop-invariant).
  fma_hint            : Restructure a*b + c patterns so the compiler emits FMA; usually automatic with -ffp-contract=fast.

LOOP STRUCTURE
  loop_invariant_hoist: Move loop-invariant computations (e.g., constant subexpressions, address calculations) outside the loop body.
  inner_loop_restrict : Eliminate conditional branches (e.g., if i==j) from the inner loop by splitting into two ranges or using a branchless mask.
  loop_tiling         : Tile a nested loop so the working set fits in L1/L2; most beneficial when inner data > cache size.

PARALLELISM
  openmp_parallel_for : Add #pragma omp parallel for with reduction clauses to the outermost independent loop; each thread gets its own private accumulator.
  openmp_simd         : Add #pragma omp simd (or #pragma GCC ivdep) to an inner loop to force vectorization when the compiler cannot prove safety automatically.
"""


# make a plan at first. at start
# 1. advertise the hardware capabilies
# 2. show statergies for this hardware
# 3. show general statergies
# 4. show much time took to run the unoptimized one
def build_plan_prompt(src: str, hw: str, base_secs: float) -> str:
    hw_section = _hw_guidance(hw)
    return f"""You are a C performance expert. Analyse the source below and produce a concrete optimization plan.

=== HARDWARE ===
{hw}

=== WHAT THIS HARDWARE CAN EXPLOIT ===
{hw_section}

=== OPTIMIZATION STRATEGIES TO CONSIDER ===
{_OPTIMIZATION_TAXONOMY}

=== TASK ===
Baseline time: {base_secs:.4f}s

Read the source carefully. Identify the actual bottlenecks (hot loops, memory layout, aliasing, etc.).
Then select up to 10 optimizations from the taxonomy above that apply to THIS code.
Order them by expected impact (highest first).

Output a JSON object — no markdown, no prose, no backticks — in exactly this shape:
{{
  "optimizations": [
    {{"id": 1, "name": "snake_case_name", "description": "one concrete sentence describing the exact change to make in this code", "risk": "low|medium|high"}},
    ...
  ]
}}

Additional rules:
- Each optimization must be independently applicable (applying one must not require another).
- Descriptions must be specific to this code (mention actual function names, variable names, or loop locations).
- Do not suggest changes to compiler flags, build system, external libraries, or NUMA.
- Prefer low/medium risk. Only include high-risk items if the expected gain is large.

SOURCE:
{src}"""


# for each optimization...
def build_apply_prompt(src: str, opt: dict, hw: str, baseline_src: str) -> str:
    return f"""You are a C performance expert. Apply EXACTLY ONE optimization to the CURRENT SOURCE.

Optimization:
  name: {opt['name']}
  description: {opt['description']}

STRICT RULES — violating any causes test failure:
1. Return ONLY a complete, compilable C source file. No markdown, no prose, no backticks.
2. Make the SMALLEST change that implements the optimization. Touch nothing else.
3. ALL constants must remain IDENTICAL to the current source.
4. ALL function signatures, struct definitions, and printf format strings must remain IDENTICAL.
5. The program must produce byte-identical stdout to the baseline.
6. Do NOT add, remove, or reorder #include lines unless strictly required by the change.
7. Do NOT modify functions unrelated to the optimization.

Hardware: {hw}

BASELINE SOURCE (read-only reference — do not deviate from its constants or output format):
{baseline_src}

CURRENT SOURCE (apply the optimization here):
{src}"""


# if an edit break the code...
# 1. show why the code broke
# 2. show the broken code
# 3. show the original c
def build_fix_prompt(code: str, reason: str, hw: str, baseline_src: str) -> str:
    return f"""The C code below failed:
{reason}

Fix ONLY the specific failure. Do not restructure. Do not add new optimizations.

STRICT RULES:
1. Return ONLY a complete, compilable C source file. No markdown, no prose, no backticks.
2. ALL constants must match the BASELINE exactly.
3. ALL printf format strings must match the BASELINE exactly.
4. Do not change functions unrelated to the failure.

BASELINE SOURCE (restore any constant or output format from here if needed):
{baseline_src}

BROKEN CODE:
{code}"""