# Convert a ChatGPT conversations.json into one Markdown file per chat.
# Usage: python export_to_markdown.py conversations.json out_folder
# Loads the whole file into memory: fine for small and medium exports.
import datetime
import json
import pathlib
import re
import sys

src, out = pathlib.Path(sys.argv[1]), pathlib.Path(sys.argv[2])
out.mkdir(parents=True, exist_ok=True)

data = json.loads(src.read_text(encoding="utf-8"))
if isinstance(data, dict):  # some exports wrap the list: {"conversations": [...]}
    data = data.get("conversations", [])


def kept_branch(conv):
    """Walk from current_node up through parent links, then reverse."""
    mapping, node, msgs = conv.get("mapping", {}), conv.get("current_node"), []
    while node in mapping:
        msg = mapping[node].get("message")
        if msg:
            msgs.append(msg)
        node = mapping[node].get("parent")
    return list(reversed(msgs))


used = set()
for conv in data:
    title = (conv.get("title") or "").strip() or "Untitled chat"
    lines = [f"# {title}", ""]
    for msg in kept_branch(conv):
        role = msg.get("author", {}).get("role")
        if msg.get("metadata", {}).get("is_visually_hidden_from_conversation"):
            continue
        if role == "assistant" and msg.get("recipient", "all") != "all":
            continue  # internal tool call
        parts = (msg.get("content") or {}).get("parts") or []
        text = "\n\n".join(p for p in parts if isinstance(p, str)).strip()
        if role in ("user", "assistant") and text:
            lines += [f"## {'You' if role == 'user' else 'ChatGPT'}", "", text, ""]
    day = datetime.datetime.fromtimestamp(conv.get("create_time") or 0).strftime("%Y-%m-%d")
    name = re.sub(r'[\\/:*?"<>|\x00-\x1f]', " ", title)[:80].strip() or "Untitled chat"
    path = out / f"{day} {name}.md"
    n = 2
    while path.name.lower() in used:
        path = out / f"{day} {name} ({n}).md"
        n += 1
    used.add(path.name.lower())
    path.write_text("\n".join(lines), encoding="utf-8")

print(f"wrote {len(used)} files to {out}")
