#!/usr/bin/env python3
"""
Generate performance profiler for a given function/module.

Usage:
    python ci/profile/generate_profile_test.py sincos16
    python ci/profile/generate_profile_test.py "fl::Perlin::pnoise2d"
    python ci/profile/generate_profile_test.py Animartrix::Chasing_Spirals
"""

import argparse
import re
import subprocess
import sys
from pathlib import Path
from typing import Any

from running_process import RunningProcess

from ci.util.global_interrupt_handler import notify_main_thread


class ProfileGenerator:
    def __init__(self, target: str):
        self.target = target
        self.test_name = self._sanitize_name(target)
        self.output_path = Path(f"tests/profile/{self.test_name}.cpp")

    def _sanitize_name(self, name: str) -> str:
        """Convert 'fl::sincos16' → 'sincos16'"""
        return (
            name.replace("::", "_")
            .replace("<", "_")
            .replace(">", "_")
            .replace(" ", "_")
            .lower()
        )

    def _detect_signature(self) -> dict[str, Any] | None:
        """
        Search codebase for function signature.
        Returns: {
            'return_type': 'void',
            'params': [('uint16_t', 'angle'), ...],
            'namespace': 'fl',
            'header': 'fl/math.h',
            'function_name': 'sincos16'
        }
        """
        # Extract function name from target (handle namespaces)
        func_name = self.target.split("::")[-1]

        # Search for function declaration using grep
        try:
            result = RunningProcess.run(
                ["git", "grep", "-n", f"\\b{func_name}\\b", "--", "*.h", "*.hpp"],
                cwd=None,
                check=False,
                timeout=30,
            )

            if result.returncode != 0:
                print(f"Warning: Could not find function '{func_name}' in codebase")
                return None

            # Parse grep output to find function declarations
            # Look for patterns like: return_type function_name(params)
            func_pattern = re.compile(
                r"^([^:]+):(\d+):\s*(?:inline\s+)?(?:static\s+)?(?:FASTLED_\w+\s+)?(\w+)\s+(\w+)\s*\("
            )

            for line in result.stdout.split("\n"):
                match = func_pattern.match(line)
                if match:
                    file_path, _line_num, return_type, found_name = match.groups()
                    if found_name == func_name:
                        # Found a match, try to parse parameters
                        # This is a simplified parser; complex signatures may need refinement
                        return {
                            "return_type": return_type,
                            "params": [],  # Simplified: empty params
                            "namespace": "fl",
                            "header": file_path.replace("src/", ""),
                            "function_name": func_name,
                        }

        except KeyboardInterrupt:
            notify_main_thread()
            raise
        except Exception as e:
            print(f"Warning: Error searching for function: {e}")

        return None

    def _generate_profiler(self, signature: dict[str, Any] | None) -> str:
        """Generate C++ profiler code from template"""
        if signature:
            target_call = f"{signature['namespace']}::{signature['function_name']}"
            header_include = f'#include "{signature["header"]}"'
        else:
            # Fallback for unknown signatures
            target_call = self.target
            header_include = '#include "FastLED.h"'

        return f'''// Auto-generated profiler for {self.target}
// Generated by: ci/profile/generate_profile_test.py

#include "FastLED.h"
{header_include}
#include "fl/stl/cstring.h"
#include "fl/stl/stdio.h"

using namespace fl;

// Benchmark configuration
static const int WARMUP_ITERATIONS = 1000;
static const int PROFILE_ITERATIONS = 100000;

// IMPORTANT: Customize this benchmark for your specific function
// This is a template - you need to:
// 1. Define appropriate test inputs
// 2. Call the target function correctly
// 3. Ensure volatile prevents optimization

__attribute__((noinline))
void benchmarkBaseline() {{
    // TODO: Customize this for {self.target}
    // Example for a simple function:
    volatile int result = 0;
    for (int i = 0; i < PROFILE_ITERATIONS; i++) {{
        // result = {target_call}(test_input);
        result += i; // Placeholder - replace with actual call
    }}
    (void)result; // Prevent optimization
}}

int main(int argc, char *argv[]) {{
    bool do_baseline = true;

    if (argc > 1) {{
        if (fl::strcmp(argv[1], "baseline") == 0) {{
            do_baseline = true;
        }} else if (fl::strcmp(argv[1], "optimized") == 0) {{
            do_baseline = false;
            fl::printf("Error: Optimized variant not implemented yet\\n");
            return 1;
        }}
    }}

    // Warmup
    for (int i = 0; i < WARMUP_ITERATIONS / PROFILE_ITERATIONS; i++) {{
        benchmarkBaseline();
    }}

    // Benchmark baseline
    if (do_baseline) {{
        fl::u32 t0 = ::micros();
        benchmarkBaseline();
        fl::u32 t1 = ::micros();
        fl::u32 elapsed_us = t1 - t0;
        fl::i64 elapsed_ns = static_cast<fl::i64>(elapsed_us) * 1000LL;
        double ns_per_call = static_cast<double>(elapsed_ns) / PROFILE_ITERATIONS;

        // Structured output for AI parsing
        fl::printf("PROFILE_RESULT:{{\\n");
        fl::printf("  \\"variant\\": \\"baseline\\",\\n");
        fl::printf("  \\"target\\": \\"{self.target}\\",\\n");
        fl::printf("  \\"total_calls\\": %d,\\n", PROFILE_ITERATIONS);
        fl::printf("  \\"total_time_ns\\": %lld,\\n", static_cast<long long>(elapsed_ns));
        fl::printf("  \\"ns_per_call\\": %.2f,\\n", ns_per_call);
        fl::printf("  \\"calls_per_sec\\": %.0f\\n", 1e9 / ns_per_call);
        fl::printf("}}\\n");
    }}

    return 0;
}}
'''

    def generate(self) -> Path:
        """Generate profiler test file"""
        signature = self._detect_signature()
        code = self._generate_profiler(signature)

        self.output_path.parent.mkdir(parents=True, exist_ok=True)
        self.output_path.write_text(code, encoding="utf-8")

        print(f"Generated profiler: {self.output_path}")
        print("\n⚠️  IMPORTANT: The generated profiler is a TEMPLATE")
        print("   You MUST customize the benchmark code for your specific function!")
        print(f"   Edit: {self.output_path}")
        return self.output_path


def main() -> int:
    parser = argparse.ArgumentParser(description="Generate performance profiler")
    parser.add_argument("target", help="Function/module to profile (e.g., sincos16)")
    args = parser.parse_args()

    generator = ProfileGenerator(args.target)
    generator.generate()
    return 0


if __name__ == "__main__":
    sys.exit(main())
