#!/usr/bin/env python3
"""
Gemma4-based Lean porting MCP server.
Finds TODO(lean-port) sorries, sends to Gemma for proof completion, validates.
"""
import json, os, re, subprocess, sys, urllib.request
from pathlib import Path
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("gemma-lean-port", log_level="WARNING")

GEMMA_URL = os.getenv("GEMMA_URL", "http://127.0.0.1:8081/v1/chat/completions")
GEMMA_MODEL = os.getenv("GEMMA_MODEL", "gemma4-12b")
LAKE_WORKDIR = os.getenv("LAKE_WORKDIR", "/home/allaun/SilverSight/0-Core-Formalism/lean/Semantics")


@mcp.tool()
def find_todo_sorries(repo_root: str = "") -> str:
    """Find all TODO(lean-port) sorry declarations in Lean files."""
    root = repo_root or LAKE_WORKDIR
    results = []
    for lean_file in Path(root).rglob("*.lean"):
        try:
            content = lean_file.read_text()
        except Exception:
            continue
        for m in re.finditer(r"TODO\(lean-port\)", content):
            line = content[:m.start()].count("\n") + 1
            results.append(f"{lean_file}:{line}")
    return "\n".join(results) or "No TODO(lean-port) found"


@mcp.tool()
def port_theorem(lean_file: str, line_no: int) -> str:
    """Send theorem context to Gemma and attempt proof. Returns result JSON."""
    lines = Path(lean_file).read_text().split("\n")
    start = max(0, line_no - 15)
    ctx = "\n".join(lines[start:line_no + 10])
    
    prompt = f"Complete this Lean theorem. Use Q16_16 fixed-point (no Float). Output ONLY the proof block starting with `:= by`.\n\n{ctx}"
    body = json.dumps({"model": GEMMA_MODEL, "messages": [{"role": "user", "content": prompt}]})
    req = urllib.request.Request(GEMMA_URL, data=body.encode(), headers={"Content-Type": "application/json"})
    
    try:
        with urllib.request.urlopen(req, timeout=120) as resp:
            data = json.loads(resp.read())
            proof = data["choices"][0]["message"]["content"]
    except Exception as e:
        return json.dumps({"status": "error", "message": str(e)})
    
    # Extract proof and apply
    proof_text = extract_proof(proof)
    apply_proof(lean_file, line_no, proof_text)
    
    # Validate
    module = lean_file.split("/")[-1].replace(".lean", "")
    ok, err = validate_build(module)
    return json.dumps({"status": "success" if ok else "failed", "proof": proof_text[:200], "error": err[:200] if err else None})


def extract_proof(text: str) -> str:
    for line in text.split("\n"):
        s = line.strip()
        if ":= by" in s:
            return s.split(":= by", 1)[-1].strip()
    return text.strip()


def apply_proof(file: str, line_no: int, proof: str) -> bool:
    lines = Path(file).read_text().split("\n")
    for i, l in enumerate(lines):
        if "sorry" in l and abs(i - line_no + 1) <= 2:
            indent = len(l) - len(l.lstrip())
            lines[i] = l.replace("sorry", ":=\n" + "\n".join(" " * (indent + 2) + p for p in proof.split("\n")))
            break
    Path(file).write_text("\n".join(lines))
    return True


def validate_build(module: str) -> tuple[bool, str]:
    result = subprocess.run(["lake", "build", module], cwd=LAKE_WORKDIR, capture_output=True, text=True, timeout=180)
    ok = result.returncode == 0 and "sorry" not in (result.stdout + result.stderr)
    return ok, (result.stdout + result.stderr)[:500]


if __name__ == "__main__":
    mcp.run(transport="stdio")
