#!/usr/bin/env python3
import json
import os
import re
import sys
import urllib.parse
import urllib.request

MCP_BASE = "http://127.0.0.1:48888"

LABEL_VERSION = "x3d model version"
LABEL_DIALOG = "Setup CLT Batch parameters"


def http_get(path, params=None, timeout=2.0):
    url = MCP_BASE + path
    if params:
        url += "?" + urllib.parse.urlencode(params)
    with urllib.request.urlopen(url, timeout=timeout) as resp:
        return resp.read().decode("utf-8")


def http_post(path, data, timeout=2.0):
    url = MCP_BASE + path
    body = urllib.parse.urlencode(data).encode("utf-8")
    req = urllib.request.Request(url, data=body, method="POST")
    with urllib.request.urlopen(req, timeout=timeout) as resp:
        return resp.read().decode("utf-8")


def parse_json(text):
    return json.loads(text)


def get_version_from_mcp():
    http_post("/mcp/button", {"label": LABEL_DIALOG})
    dialog = None
    for _ in range(25):
        dialog = parse_json(http_get("/mcp/dialog"))
        if dialog.get("ok") and dialog.get("dialog") is not None:
            break
        import time
        time.sleep(0.2)
    if not dialog or dialog.get("dialog") is None:
        raise RuntimeError("No active MCP dialog")
    dialog_id = dialog["dialog"].get("id")
    fields = dialog["dialog"].get("fields", [])
    version = None
    for f in fields:
        if f.get("label") == LABEL_VERSION:
            version = f.get("default")
            break
    if version is None:
        raise RuntimeError("x3d model version not found in MCP dialog")
    # cancel dialog to avoid applying defaults
    if dialog_id:
        http_post("/mcp/dialog/submit", {"id": dialog_id, "ok": "0"})
    else:
        http_post("/mcp/dialog/submit", {"ok": "0"})
    return version


def read_list_file(list_path):
    data = parse_json(http_get("/mcp/fs/read", {"path": list_path, "offset": 0, "maxBytes": 1024 * 1024}, timeout=30.0))
    if not data.get("ok"):
        raise RuntimeError("Failed to read list file")
    return data.get("data", "")


def parse_set_paths(list_text, list_path):
    base_path = os.path.dirname(list_path)
    root_dir = None
    linked_models = None
    x3d_dir = None
    for raw in list_text.splitlines():
        line = raw.split("#", 1)[0].strip()
        if not line:
            continue
        tokens = re.split(r"[\s,;=]+", line)
        if len(tokens) >= 2 and tokens[0].upper() == "SET":
            key = tokens[1]
            val = tokens[2] if len(tokens) >= 3 else ""
            if key == "rootDirectory":
                root_dir = val
            elif key == "linkedModels":
                linked_models = val
            elif key == "x3dDirectory":
                x3d_dir = val
    if root_dir:
        base_path = os.path.normpath(os.path.join(base_path, root_dir))
    chosen = x3d_dir or linked_models
    if not chosen:
        raise RuntimeError("x3dDirectory or linkedModels not found in list file")
    models_dir = os.path.normpath(os.path.join(base_path, chosen))
    return models_dir


def parse_sequences(list_text):
    seqs = []
    lines = list_text.splitlines()
    for idx, raw in enumerate(lines):
        stripped = raw.lstrip()
        if not stripped or stripped.startswith("#"):
            continue
        line = raw.split("#", 1)[0].strip()
        if not line:
            continue
        tokens = re.split(r"[\s,;=]+", line)
        if len(tokens) == 0:
            continue
        if tokens[0].upper() == "SET":
            continue
        seqs.append((tokens[0], idx))
    return seqs, lines


def glob_v_dirs(version, models_dir):
    pattern = f"{models_dir}/**/{version}"
    data = parse_json(http_get("/mcp/fs/glob", {"pattern": pattern, "max": 200000, "maxDepth": 4}, timeout=30.0))
    if not data.get("ok"):
        raise RuntimeError("Failed to glob version dirs")
    return data.get("matches", [])


def main():
    if len(sys.argv) < 2:
        raise SystemExit("Usage: mcp_filter_list_by_model_version.py <list_path> [version]")
    list_path = sys.argv[1]
    version = sys.argv[2] if len(sys.argv) > 2 else get_version_from_mcp()
    list_text = read_list_file(list_path)
    models_dir = parse_set_paths(list_text, list_path)
    seqs, lines = parse_sequences(list_text)
    if not seqs:
        raise RuntimeError("No sequences found")

    matches = glob_v_dirs(version, models_dir)
    model_dir_norm = os.path.normpath(models_dir)
    scene_ts = []
    for m in matches:
        m_norm = os.path.normpath(m)
        if not m_norm.startswith(model_dir_norm + os.sep):
            continue
        parent = os.path.dirname(m_norm)
        ts = os.path.basename(parent)
        if ts:
            scene_ts.append(ts)
    scene_ts = sorted(set(scene_ts))

    keep = set()
    if scene_ts:
        i = 0
        for idx, (seq, line_idx) in enumerate(seqs):
            next_seq = seqs[idx + 1][0] if idx + 1 < len(seqs) else None
            while i < len(scene_ts) and scene_ts[i] < seq:
                i += 1
            if i < len(scene_ts):
                if next_seq is None or scene_ts[i] < next_seq:
                    keep.add(seq)

    out_lines = []
    for raw in lines:
        stripped = raw.lstrip()
        if not stripped:
            out_lines.append(raw)
            continue
        if stripped.startswith("#"):
            out_lines.append(raw)
            continue
        line_no_comment = raw.split("#", 1)[0].strip()
        if not line_no_comment:
            out_lines.append(raw)
            continue
        tokens = re.split(r"[\s,;=]+", line_no_comment)
        if tokens and tokens[0].upper() == "SET":
            out_lines.append(raw)
            continue
        seq = tokens[0]
        if seq in keep:
            out_lines.append(raw)
        else:
            out_lines.append("#" + raw)

    base_name = os.path.basename(list_path)
    if base_name.endswith(".list"):
        out_name = base_name[:-5] + f"-{version}.list"
    else:
        out_name = base_name + f"-{version}.list"
    out_path = os.path.join(os.path.dirname(list_path), out_name)
    with open(out_path, "w", encoding="utf-8") as f:
        f.write("\n".join(out_lines) + ("\n" if out_lines else ""))

    print(f"Version: {version}")
    print(f"Models dir: {models_dir}")
    print(f"Sequences kept: {len(keep)} / {len(seqs)}")
    print(f"Output: {out_path}")


if __name__ == "__main__":
    main()
