#!/usr/bin/env python3
import json
import re
import sys
from pathlib import Path

MODEL_KEYS = [
    "GPT5_3_CODEX_MC",
    "GPT5_4_MC",
    "OPUS_4_6_MC",
    "KIMI_K2_5_MC",
    "GLM_5_MC",
    "MINIMAX_2_5_MC",
    "GEMINI_3_MC",
    "SONNET_4_5_MC",
]

ALIASES = {
    "gpt5_3_codex_mc": "GPT5_3_CODEX_MC",
    "gpt5.3": "GPT5_3_CODEX_MC",
    "gpt-5.3": "GPT5_3_CODEX_MC",
    "gpt-5.3 codex": "GPT5_3_CODEX_MC",
    "codex": "GPT5_3_CODEX_MC",
    "gpt5_4_mc": "GPT5_4_MC",
    "gpt5.4": "GPT5_4_MC",
    "gpt-5.4": "GPT5_4_MC",
    "opus": "OPUS_4_6_MC",
    "opus 4.6": "OPUS_4_6_MC",
    "claude opus": "OPUS_4_6_MC",
    "kimi": "KIMI_K2_5_MC",
    "kimi k2.5": "KIMI_K2_5_MC",
    "glm": "GLM_5_MC",
    "glm 5": "GLM_5_MC",
    "minimax": "MINIMAX_2_5_MC",
    "minimax 2.5": "MINIMAX_2_5_MC",
    "gemini": "GEMINI_3_MC",
    "gemini 3": "GEMINI_3_MC",
    "sonnet": "SONNET_4_5_MC",
    "sonnet 4.5": "SONNET_4_5_MC",
    "claude sonnet": "SONNET_4_5_MC",
}

DEFAULTS = {
    "name": "llm-spatial-ipd-skill-run",
    "description": "LLM spatial IPD run created from soft params.",
    "seed": 20260311,
    "gridSize": 12,
    "generations": 24,
    "roundsPerGeneration": 8,
    "neighborhood": "moore",
    "updateRule": "imitate_best",
    "temptation": 5,
    "reward": 3,
    "punishment": 1,
    "sucker": 0,
    "mutationRate": 0.002,
    "noiseRate": 0.01,
    "promptVersion": "v1",
    "gatewayEnvVar": "VERCEL_AI_GATEWAY_API_KEY",
    "initialAssignmentMode": "weighted-random",
    "modelWeights": {key: 1 for key in MODEL_KEYS},
    "notes": "Generated from Skills/llm-spatial-ipd-runner.",
}


def parse_request(text: str):
    lower = text.lower()
    config = json.loads(json.dumps(DEFAULTS))

    m = re.search(r"grid\s*(\d+)\s*x\s*(\d+)", lower)
    if m and m.group(1) == m.group(2):
        config["gridSize"] = int(m.group(1))
    else:
        m = re.search(r"(\d+)\s*x\s*(\d+)\s*grid", lower)
        if m and m.group(1) == m.group(2):
            config["gridSize"] = int(m.group(1))

    m = re.search(r"(\d+)\s*(steps|generations|gens)", lower)
    if m:
        config["generations"] = int(m.group(1))

    m = re.search(r"(\d+)\s*(rounds|rounds per step|rounds per generation)", lower)
    if m:
        config["roundsPerGeneration"] = int(m.group(1))

    m = re.search(r"seed\s*(\d+)", lower)
    if m:
        config["seed"] = int(m.group(1))

    if "von neumann" in lower or "vonneumann" in lower or "4-neighbor" in lower:
        config["neighborhood"] = "vonneumann"
    if "moore" in lower or "8-neighbor" in lower:
        config["neighborhood"] = "moore"

    if "replicator" in lower:
        config["updateRule"] = "replicator"
    if "imitate best" in lower:
        config["updateRule"] = "imitate_best"

    for field, pattern in [
        ("temptation", r"temptation\s*([0-9]*\.?[0-9]+)"),
        ("reward", r"reward\s*([0-9]*\.?[0-9]+)"),
        ("punishment", r"punishment\s*([0-9]*\.?[0-9]+)"),
        ("sucker", r"sucker\s*([0-9]*\.?[0-9]+)"),
    ]:
        m = re.search(pattern, lower)
        if m:
            config[field] = float(m.group(1))

    m = re.search(r"noise\s*([0-9]*\.?[0-9]+)\s*%", lower)
    if m:
        config["noiseRate"] = float(m.group(1)) / 100
    m = re.search(r"noise\s*([0-9]*\.?[0-9]+)", lower)
    if m and "%" not in m.group(0):
        config["noiseRate"] = float(m.group(1))

    m = re.search(r"mutation\s*([0-9]*\.?[0-9]+)\s*%", lower)
    if m:
        config["mutationRate"] = float(m.group(1)) / 100
    m = re.search(r"mutation\s*([0-9]*\.?[0-9]+)", lower)
    if m and "%" not in m.group(0):
        config["mutationRate"] = float(m.group(1))

    if "all registered models" in lower or "all models" in lower:
        config["modelWeights"] = {key: 1 for key in MODEL_KEYS}
    else:
        selected = []
        for alias, key in ALIASES.items():
            if alias in lower and key not in selected:
                selected.append(key)
        if selected:
            config["modelWeights"] = {key: (1 if key in selected else 0) for key in MODEL_KEYS}

    safe_name = re.sub(r"[^a-z0-9]+", "-", lower).strip("-")[:80] or "llm-spatial-ipd-skill-run"
    config["name"] = safe_name
    config["description"] = text.strip() or DEFAULTS["description"]
    config["notes"] = f"Generated from soft request: {text.strip()}"
    return config


def main():
    if len(sys.argv) != 3:
        print("Usage: build_config.py '<soft request>' <output_path>", file=sys.stderr)
        sys.exit(1)

    request = sys.argv[1]
    output_path = Path(sys.argv[2])
    output_path.parent.mkdir(parents=True, exist_ok=True)
    config = parse_request(request)
    output_path.write_text(json.dumps(config, indent=2) + "\n")
    print(str(output_path))


if __name__ == "__main__":
    main()
