#!/usr/bin/env bash
# Generate a filterable web gallery of mmdflux SVG output.
# Renders all fixture × engine × preset permutations; skips invalid combos silently.
#
# Usage:
#   scripts/svg-gallery
#   scripts/svg-gallery --out /tmp/my-gallery
#   scripts/svg-gallery --no-open
#
# Environment overrides (comma-separated):
#   ENGINES="flux-layered,mermaid-layered"
#   PRESETS="bezier,straight,step,smoothstep"
#   FAMILIES="flowchart,class"
#   FIXTURES="simple,chain"   # stem substring match

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
MMDFLUX_BIN="$REPO_ROOT/target/debug/mmdflux"

OUT_DIR="${OUT_DIR:-$REPO_ROOT/scripts/out/svg-gallery-$(date +%Y%m%d-%H%M%S)}"
AUTO_OPEN=1

while [[ $# -gt 0 ]]; do
  case "$1" in
    --out) OUT_DIR="$2"; shift 2 ;;
    --no-open) AUTO_OPEN=0; shift ;;
    *) printf 'Unknown argument: %s\n' "$1" >&2; exit 1 ;;
  esac
done

mkdir -p "$OUT_DIR"

# --- Config (env overrideable) ---

split_csv() { printf '%s' "$1" | tr ',' '\n' | grep -v '^$'; }

read_csv_array() {
  local -a result=()
  while IFS= read -r item; do
    [[ -n "$item" ]] && result+=("$item")
  done < <(split_csv "$1")
  printf '%s\n' "${result[@]}"
}

ENGINES=()
while IFS= read -r e; do ENGINES+=("$e"); done < <(read_csv_array "${ENGINES:-flux-layered,mermaid-layered}")

PRESETS=()
while IFS= read -r p; do PRESETS+=("$p"); done < <(read_csv_array "${PRESETS:-bezier,straight,step,smoothstep}")

FAMILIES=()
while IFS= read -r f; do FAMILIES+=("$f"); done < <(read_csv_array "${FAMILIES:-flowchart,class}")

# --- Build ---

printf 'Building mmdflux...\n'
cargo build --quiet --manifest-path "$REPO_ROOT/Cargo.toml" --bin mmdflux
printf 'Output: %s\n\n' "$OUT_DIR"

# --- Render loop ---
# Collect metadata for HTML generation alongside rendering.

MANIFEST=()   # "family|fixture_stem|engine|preset|svg_filename" per successful render

n_rendered=0
n_skipped=0

for family in "${FAMILIES[@]}"; do
  fixture_dir="$REPO_ROOT/tests/fixtures/$family"
  [[ -d "$fixture_dir" ]] || continue

  while IFS= read -r fixture_path; do
    fixture_name="$(basename "$fixture_path")"
    stem="${fixture_name%.mmd}"

    # Optional fixture name filter
    if [[ -n "${FIXTURES:-}" ]]; then
      match=0
      while IFS= read -r pat; do
        [[ "$stem" == *"$pat"* ]] && match=1 && break
      done < <(split_csv "$FIXTURES")
      [[ $match -eq 1 ]] || continue
    fi

    for engine in "${ENGINES[@]}"; do
      for preset in "${PRESETS[@]}"; do
        slug="${family}_${stem}_${engine}_${preset}"
        out_svg="$OUT_DIR/${slug}.svg"

        if "$MMDFLUX_BIN" \
            --format svg \
            --layout-engine "$engine" \
            --edge-preset "$preset" \
            "$fixture_path" >"$out_svg" 2>/dev/null
        then
          MANIFEST+=("${family}|${stem}|${engine}|${preset}|${slug}.svg")
          n_rendered=$((n_rendered + 1))
          printf '  OK  %s\n' "$slug"
        else
          rm -f "$out_svg"
          n_skipped=$((n_skipped + 1))
          printf ' SKIP %s\n' "$slug"
        fi
      done
    done
  done < <(find "$fixture_dir" -maxdepth 1 -type f -name '*.mmd' | sort)
done

printf '\nRendered: %d  Skipped (invalid combos): %d\n' "$n_rendered" "$n_skipped"

# --- Generate HTML ---

GALLERY_HTML="$OUT_DIR/gallery.html"

# Build JS arrays of distinct values for filter checkboxes
js_engines="$(printf '%s\n' "${ENGINES[@]}" | sort -u | awk '{printf "\"%s\",", $0}' | sed 's/,$//')"
js_presets="$(printf '%s\n' "${PRESETS[@]}" | sort -u | awk '{printf "\"%s\",", $0}' | sed 's/,$//')"
js_families="$(printf '%s\n' "${FAMILIES[@]}" | sort -u | awk '{printf "\"%s\",", $0}' | sed 's/,$//')"

{
cat <<'HTML_HEAD'
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>mmdflux SVG Gallery</title>
  <style>
    :root {
      --bg: #0b1020; --fg: #e8ebf3; --muted: #98a1b3;
      --card: #141a2b; --border: #2a334c;
    }
    * { box-sizing: border-box; }
    body { margin: 0; background: var(--bg); color: var(--fg);
           font: 14px/1.5 ui-sans-serif, -apple-system, Segoe UI, sans-serif; }
    header { padding: 16px 20px 0; max-width: 1800px; margin: 0 auto; }
    h1 { margin: 0 0 4px; font-size: 22px; }
    .subtitle { color: var(--muted); margin: 0 0 12px; font-size: 13px; }
    .controls { display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
                padding: 10px 20px; max-width: 1800px; margin: 0 auto;
                border-bottom: 1px solid var(--border); }
    .controls input[type=text] {
      background: #111827; color: var(--fg); border: 1px solid var(--border);
      border-radius: 8px; padding: 6px 10px; min-width: 240px; }
    .controls label { color: var(--muted); display: flex; align-items: center; gap: 4px;
                      cursor: pointer; user-select: none; font-size: 13px; }
    .sep { width: 1px; height: 20px; background: var(--border); }
    .count { color: var(--muted); font-size: 12px; margin-left: auto; }
    main { max-width: 1800px; margin: 0 auto; padding: 14px 20px; }
    .grid { display: grid;
            grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
            gap: 12px; }
    .card { background: var(--card); border: 1px solid var(--border);
            border-radius: 10px; overflow: hidden; }
    .card-header { padding: 8px 10px; display: flex; flex-wrap: wrap;
                   gap: 5px; align-items: center; border-bottom: 1px solid var(--border); }
    .name { font-family: ui-monospace, monospace; font-size: 12px;
            font-weight: 600; flex: 1; min-width: 0;
            overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .badge { font-size: 10px; font-weight: 700; text-transform: uppercase;
             letter-spacing: .4px; border-radius: 999px; padding: 2px 7px;
             border: 1px solid; white-space: nowrap; }
    /* family */
    .fam-flowchart { color: #bae6fd; background: #0c4a6e44; border-color: #0ea5e9; }
    .fam-class     { color: #fed7aa; background: #7c2d1244; border-color: #f97316; }
    /* engine */
    .eng-flux     { color: #d9f99d; background: #36531444; border-color: #4d7c0f; }
    .eng-mermaid  { color: #e9d5ff; background: #4c1d9544; border-color: #7c3aed; }
    /* preset */
    .pre-bezier     { color: #bfdbfe; background: #1e3a8a44; border-color: #3b82f6; }
    .pre-straight   { color: #fde68a; background: #78350f44; border-color: #d97706; }
    .pre-step       { color: #fca5a5; background: #7f1d1d44; border-color: #ef4444; }
    .pre-smoothstep { color: #a7f3d0; background: #064e3b44; border-color: #10b981; }
    .card-body { background: #fff; line-height: 0; }
    .card-body img { width: 100%; height: 260px; object-fit: contain;
                     background: #fff; display: block; }
    .hidden { display: none !important; }
    .no-results { color: var(--muted); padding: 40px; text-align: center; font-size: 15px; }
  </style>
</head>
<body>
<header>
  <h1>mmdflux SVG Gallery</h1>
  <p class="subtitle" id="subtitle">Loading…</p>
</header>
<div class="controls">
  <input id="search" type="text" placeholder="Filter fixture name…" oninput="applyFilters()" />
  <span class="sep"></span>
HTML_HEAD

# Family checkboxes
for family in "${FAMILIES[@]}"; do
  printf '  <label><input type="checkbox" class="fam-cb" value="%s" checked onchange="applyFilters()"> %s</label>\n' "$family" "$family"
done

printf '  <span class="sep"></span>\n'

# Engine checkboxes
for engine in "${ENGINES[@]}"; do
  printf '  <label><input type="checkbox" class="eng-cb" value="%s" checked onchange="applyFilters()"> %s</label>\n' "$engine" "$engine"
done

printf '  <span class="sep"></span>\n'

# Preset checkboxes
for preset in "${PRESETS[@]}"; do
  printf '  <label><input type="checkbox" class="pre-cb" value="%s" checked onchange="applyFilters()"> %s</label>\n' "$preset" "$preset"
done

cat <<'HTML_GRID_START'
  <span class="count" id="count"></span>
</div>
<main>
<div class="grid" id="grid">
HTML_GRID_START

# Emit one card per manifest entry
for entry in "${MANIFEST[@]}"; do
  IFS='|' read -r family stem engine preset svg_file <<< "$entry"

  # Derive badge CSS classes
  fam_class="fam-${family}"
  eng_key="${engine%%-*}"  # flux, mermaid, elk
  eng_class="eng-${eng_key}"
  pre_class="pre-${preset}"

  cat <<CARD
<div class="card" data-family="${family}" data-engine="${engine}" data-preset="${preset}" data-fixture="${stem}">
  <div class="card-header">
    <span class="name" title="${stem}">${stem}</span>
    <span class="badge ${fam_class}">${family}</span>
    <span class="badge ${eng_class}">${engine}</span>
    <span class="badge ${pre_class}">${preset}</span>
  </div>
  <div class="card-body">
    <img src="${svg_file}" loading="lazy" alt="${stem} ${engine} ${preset}" />
  </div>
</div>
CARD
done

# JS variables derived from rendered data
printf '<div class="no-results hidden" id="no-results">No matching renders.</div>\n'

} > "$GALLERY_HTML"

# Append JS footer
cat >> "$GALLERY_HTML" <<HTML_FOOT
</div>
</main>
<script>
  const total = ${n_rendered};

  function applyFilters() {
    const search = document.getElementById('search').value.trim().toLowerCase();
    const fams   = new Set([...document.querySelectorAll('.fam-cb:checked')].map(cb => cb.value));
    const engs   = new Set([...document.querySelectorAll('.eng-cb:checked')].map(cb => cb.value));
    const pres   = new Set([...document.querySelectorAll('.pre-cb:checked')].map(cb => cb.value));

    let visible = 0;
    document.querySelectorAll('.card').forEach(card => {
      const show = fams.has(card.dataset.family)
        && engs.has(card.dataset.engine)
        && pres.has(card.dataset.preset)
        && (!search || card.dataset.fixture.includes(search));
      card.classList.toggle('hidden', !show);
      if (show) visible++;
    });

    document.getElementById('count').textContent = visible + ' / ' + total;
    document.getElementById('no-results').classList.toggle('hidden', visible > 0);
    document.getElementById('subtitle').textContent =
      total + ' renders — ' + ${n_skipped} + ' combos skipped (invalid engine/preset)';
  }

  applyFilters();
</script>
</body>
</html>
HTML_FOOT

printf '\nGallery: %s\n' "$GALLERY_HTML"

if [[ $AUTO_OPEN -eq 1 ]]; then
  if command -v open &>/dev/null; then
    open "$GALLERY_HTML"
  elif command -v xdg-open &>/dev/null; then
    xdg-open "$GALLERY_HTML"
  fi
fi
