import argparse
import glob
import json
import os
import subprocess
import urllib.request

BASE_URL = os.environ.get("AI_BUILDER_BASE_URL", "https://space.ai-builders.com/backend/v1")
API_KEY = os.environ.get("AI_BUILDER_TOKEN", "")
WORKDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "workspace"))


def safe_path(rel_path: str) -> str:
    target = os.path.abspath(os.path.join(WORKDIR, rel_path))
    if not (target == WORKDIR or target.startswith(WORKDIR + os.sep)):
        raise ValueError(f"Path outside workspace (only files inside workspace/ are allowed): {rel_path}")
    return target


def read_file(path: str) -> str:
    try:
        full = safe_path(path)
        with open(full, "r", encoding="utf-8") as f:
            lines = f.readlines()
        return "".join(f"{i+1}: {line}" for i, line in enumerate(lines))
    except Exception as e:
        return f"Read failed: {e}. Check that the file path exists inside workspace/."


def write_file(path: str, content: str) -> str:
    try:
        full = safe_path(path)
        os.makedirs(os.path.dirname(full), exist_ok=True)
        with open(full, "w", encoding="utf-8") as f:
            f.write(content)
        return f"Wrote {path} ({len(content)} bytes). Next step: run tests to verify your changes."
    except Exception as e:
        return f"Write failed: {e}"


def run_bash(command: str) -> str:
    try:
        res = subprocess.run(
            command, shell=True, cwd=WORKDIR, capture_output=True, text=True, timeout=15
        )
        out = (res.stdout + res.stderr).strip()
        if len(out) > 2000:
            out = out[:2000] + "\n...[output truncated]"
        return f"exit_code={res.returncode}\n{out}"
    except Exception as e:
        return f"Command execution error: {e}"


def load_skill_index() -> str:
    entries = []
    for p in sorted(glob.glob(os.path.join(WORKDIR, ".agents/skills/*/SKILL.md"))):
        rel = os.path.relpath(p, WORKDIR)
        name, desc = os.path.basename(os.path.dirname(p)), ""
        with open(p, "r", encoding="utf-8") as f:
            for line in f:
                if line.startswith("name:"):
                    name = line.split(":", 1)[1].strip()
                elif line.startswith("description:"):
                    desc = line.split(":", 1)[1].strip()
        entries.append(f"- {name} ({rel}): {desc}")
    return "\n".join(entries)


TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "read_file",
            "description": "Read a text file inside the workspace and return its contents with line numbers. Also use this to read SKILL.md files under .agents/skills/ on demand.",
            "parameters": {
                "type": "object",
                "properties": {"path": {"type": "string", "description": "File path relative to the workspace root"}},
                "required": ["path"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "write_file",
            "description": "Write full text content to a file path inside the workspace.",
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {"type": "string", "description": "File path relative to the workspace root"},
                    "content": {"type": "string", "description": "Full text content to write"},
                },
                "required": ["path", "content"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "bash",
            "description": "Execute a shell command inside the workspace directory (such as running unittest or CLI scripts) and return its exit code and output.",
            "parameters": {
                "type": "object",
                "properties": {"command": {"type": "string", "description": "Shell command to run"}},
                "required": ["command"],
            },
        },
    },
]


def call_llm(model: str, messages: list) -> dict:
    req = urllib.request.Request(
        f"{BASE_URL}/chat/completions",
        data=json.dumps({"model": model, "messages": messages, "tools": TOOLS, "temperature": 0.0}).encode("utf-8"),
        headers={"Content-Type": "application/json", "Authorization": f"Bearer {API_KEY}"},
    )
    with urllib.request.urlopen(req, timeout=60) as resp:
        return json.loads(resp.read().decode("utf-8"))


def run_agent(task: str, model: str = "deepseek", max_turns: int = 10):
    skill_index = load_skill_index()
    sys_prompt = (
        "You are a minimal coding agent working inside a controlled workspace.\n"
        "When a task touches a specific domain, first call read_file to read the matching SKILL.md from the directory below and strictly follow its checklist and CLI verification rules. "
        "After modifying code, always run tests with bash until every check passes before giving your final report.\n\n"
        f"Available Skills (summaries only; read full file on demand):\n{skill_index}"
    )
    messages = [{"role": "system", "content": sys_prompt}, {"role": "user", "content": task}]
    for turn in range(1, max_turns + 1):
        resp = call_llm(model, messages)
        msg = resp["choices"][0]["message"]
        messages.append(msg)
        tool_calls = msg.get("tool_calls") or []
        if not tool_calls:
            print(f"\n[Turn {turn} · Done]\n{msg.get('content', '').strip()}")
            return
        for tc in tool_calls:
            fn = tc["function"]["name"]
            args = json.loads(tc["function"]["arguments"])
            print(f"[Turn {turn} · Tool Call] {fn}({json.dumps(args, ensure_ascii=False)})")
            if fn == "read_file":
                out = read_file(args["path"])
            elif fn == "write_file":
                out = write_file(args["path"], args["content"])
            elif fn == "bash":
                out = run_bash(args["command"])
            else:
                out = f"Unknown tool: {fn}"
            first_line = out.splitlines()[0] if out else ""
            print(f"  -> {first_line}")
            messages.append({"role": "tool", "tool_call_id": tc["id"], "content": out})


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--model", default="deepseek")
    parser.add_argument(
        "--task",
        default="Inspect why settle_order in settlement.py is failing tests, fix it according to the team's settlement reconciliation checklist, and pass all verification checks.",
    )
    args = parser.parse_args()
    run_agent(args.task, args.model)
