#!/usr/bin/env bash
# Read/write run.config.toml under RUN_DIR (.run/ for config layout).

save_config_json() {
  local answers_path="$1"
  local target="${WORKSPACE_CONFIG:?}"
  # Always write TOML going forward.
  case "${target}" in
    *.json) target="${RUN_DIR}/run.config.toml"; WORKSPACE_CONFIG="${target}"; export WORKSPACE_CONFIG ;;
  esac
  python3 - "${target}" "${answers_path}" <<'PY'
import json, os, re, sys

target, answers_path = sys.argv[1], sys.argv[2]
answers = {}
with open(answers_path, encoding="utf-8") as fh:
    for line in fh:
        line = line.rstrip("\n")
        if "=" not in line:
            continue
        key, value = line.split("=", 1)
        answers[key] = value

data = {}
essential = None
existing_path = target
if not os.path.isfile(existing_path):
    alt = os.path.join(os.path.dirname(target), "run.config.json")
    if os.path.isfile(alt):
        existing_path = alt

if os.path.isfile(existing_path):
    with open(existing_path, encoding="utf-8") as fh:
        text = fh.read()
    if existing_path.endswith(".json"):
        existing = json.loads(text)
        if isinstance(existing, dict):
            for key in ("essentials", "essential"):
                if isinstance(existing.get(key), dict):
                    essential = existing[key]
                    break
            for key, value in existing.items():
                if key.startswith("_") or key in ("essential", "essentials"):
                    continue
                if isinstance(value, dict):
                    data.update(value)
                else:
                    data[key] = value
    else:
        try:
            import tomllib
        except ImportError:
            tomllib = None
        if tomllib is not None:
            parsed = tomllib.loads(text)
            for key in ("essentials", "essential"):
                if isinstance(parsed.get(key), dict):
                    essential = parsed[key]
                    break

for key, value in answers.items():
    if value in ("true", "false"):
        data[key] = value == "true"
    elif value.isdigit():
        data[key] = int(value)
    else:
        data[key] = value

# Grouped the way the questions are asked, as one table per section.
GROUPS = [
    ("project", ["COMPOSE_PROJECT_NAME", "PROJECT_LABEL"]),
    ("repositories", ["BACKEND_DIR", "BACKEND_SUBDIR", "FRONTEND_DIR"]),
    ("backend", ["BACKEND_STACK", "BACKEND_INSTALL_CMD", "BACKEND_BUILD_CMD",
                 "BACKEND_START_CMD", "BACKEND_MIGRATE_CMD", "BACKEND_SEED_CMD",
                 "BACKEND_QUEUE_CMD", "BACKEND_SCHEDULE_CMD",
                 "BACKEND_HEALTH_PATH", "BACKEND_LOGIN_PATH",
                 "RUN_QUEUE", "RUN_SCHEDULER"]),
    ("apps", ["WEB_APP", "WEB_CMD",
              "RUN_ADMIN", "ADMIN_APP", "ADMIN_CMD",
              "RUN_LANDING", "LANDING_APP", "LANDING_CMD",
              "RUN_MOBILE", "MOBILE_APP", "MOBILE_CMD",
              "RUN_DESKTOP", "DESKTOP_STACK", "DESKTOP_APP", "DESKTOP_CMD",
              "DESKTOP_HOST_CMD", "EXTRA_DEPS_APPS", "EXTRA_APPS"]),
    ("infrastructure", ["DB_ENGINE", "DB_DATABASE", "DB_USERNAME", "DB_PASSWORD",
                        "RUN_MIGRATIONS", "RUN_SEEDERS", "RUN_REDIS",
                        "RUN_MAILPIT", "RUN_MINIO", "MINIO_BUCKET",
                        "MINIO_ROOT_USER", "MINIO_ROOT_PASSWORD"]),
    ("deploy", ["DEPLOY_"]),
    ("ports", ["_PORT"]),
    ("urls", ["VITE_", "EXPO_", "REACT_NATIVE_"]),
    ("docker", ["_MEMORY_LIMIT", "_CPU_LIMIT", "DOCKER_SHM_SIZE"]),
    ("other", []),
]


def rank(key):
    for index, (_, group) in enumerate(GROUPS):
        for position, entry in enumerate(group):
            if key == entry:
                return (index, position)
            if entry.endswith("_") and key.startswith(entry):
                return (index, position)
            if entry.startswith("_") and key.endswith(entry):
                return (index, position)
    return (len(GROUPS) - 1, 0)


apps_index = next(i for i, (name, _) in enumerate(GROUPS) if name == "apps")
extra = [a.split(":")[0] for a in str(data.get("EXTRA_APPS", "")).split()]
placed = {}
for offset, app in enumerate(extra):
    prefix = re.sub(r"[^A-Z0-9]", "_", app.upper()) + "_"
    for key in data:
        if key.startswith(prefix) and not key.endswith("_PORT"):
            placed[key] = (apps_index, len(GROUPS[apps_index][1]) + offset)

sections = {name: {} for name, _ in GROUPS}
for key in sorted(data, key=lambda k: (placed.get(k) or rank(k), k)):
    if key.startswith("_"):
        continue
    index, _ = placed.get(key) or rank(key)
    sections[GROUPS[index][0]][key] = data[key]

def emit_value(value):
    if isinstance(value, bool):
        return "true" if value else "false"
    if isinstance(value, int) and not isinstance(value, bool):
        return str(value)
    if isinstance(value, float):
        return repr(value)
    if value is None:
        return '""'
    text = str(value)
    escaped = text.replace("\\", "\\\\").replace('"', '\\"')
    return f'"{escaped}"'

lines = []
for name, _ in GROUPS:
    section = sections[name]
    if not section:
        continue
    lines.append(f"[{name}]")
    for key, value in section.items():
        lines.append(f"{key} = {emit_value(value)}")
    lines.append("")
    if name == "infrastructure" and isinstance(essential, dict):
        lines.append("[essentials]")
        for svc, opts in essential.items():
            if str(svc).startswith("_"):
                continue
            enabled = True
            if isinstance(opts, bool):
                enabled = opts
            elif isinstance(opts, dict):
                enabled = True
            else:
                enabled = str(opts).lower() in ("true", "1", "yes", "y", "on")
            lines.append(f"{svc} = {'true' if enabled else 'false'}")
        lines.append("")

tmp = target + ".tmp"
with open(tmp, "w", encoding="utf-8") as fh:
    fh.write("\n".join(lines).rstrip() + "\n")
os.replace(tmp, target)
# Drop a sibling JSON once TOML is the source of truth.
json_sibling = os.path.join(os.path.dirname(target), "run.config.json")
if os.path.isfile(json_sibling):
    os.remove(json_sibling)
PY
}
