#!/usr/bin/env zsh
set -euo pipefail

campaign="${1:-}"
page="${2:-}"
desktop_url="${3:-${DESKTOP_URL:-}}"
mobile_url="${4:-${MOBILE_URL:-}}"

if [[ -z "$campaign" || -z "$page" ]]; then
  echo "usage: scripts/export-exportables.v0.1.6.zsh <campaign> <page> [desktop_url] [mobile_url]"
  exit 1
fi

if [[ -z "${FIGMA_TOKEN:-}" ]]; then
  echo "ERROR Missing FIGMA_TOKEN"
  exit 1
fi

# STREAM_PATH_NOTE: "awareness" is the hardcoded default stream name.
preflight_json="campaigns/content/$campaign/awareness/_sologen/json/preflight.json"
pf_filekey=""
if [[ -z "$desktop_url" || -z "$mobile_url" ]]; then
  if [[ -s "$preflight_json" ]]; then
    pf_pair="$(node -e '
const fs=require("fs");
const path=process.argv[1];
const page=process.argv[2];
try{
  const j=JSON.parse(fs.readFileSync(path,"utf8"));
  const screens=Array.isArray(j?.screens)?j.screens:[];
  const hit=screens.find(s=>String(s?.id||"")===String(page));
  if(!hit){ process.exit(0); }
  process.stdout.write((hit.desktopUrl||"")+"\t"+(hit.mobileUrl||"")+"\t"+(j?.fileKey||""));
}catch(_e){}
' "$preflight_json" "$page")"
    if [[ -n "$pf_pair" ]]; then
      pf_desktop="${pf_pair%%$'\t'*}"
      rest="${pf_pair#*$'\t'}"
      pf_mobile="${rest%%$'\t'*}"
      pf_filekey="${rest#*$'\t'}"
      [[ -z "$desktop_url" ]] && desktop_url="$pf_desktop"
      [[ -z "$mobile_url" ]] && mobile_url="$pf_mobile"
    fi
  fi
fi

if [[ -z "$desktop_url" && -z "$mobile_url" ]]; then
  echo "ERROR Missing DESKTOP_URL/MOBILE_URL env vars or pass desktop_url/mobile_url as args."
  exit 1
fi

extract_file_key(){ printf '%s' "$1" | sed -En 's#^(https?://|figma://)[^/]+/(file|design|proto)/([A-Za-z0-9_-]+).*#\3#p' | head -n1; }

filekey=""
if [[ -n "$desktop_url" ]]; then filekey="$(extract_file_key "$desktop_url")"; fi
if [[ -z "$filekey" && -n "$mobile_url" ]]; then filekey="$(extract_file_key "$mobile_url")"; fi
if [[ -z "$filekey" && -n "$pf_filekey" ]]; then filekey="$pf_filekey"; fi
if [[ -z "$filekey" && -n "${FIGMA_FILE_KEY:-}" ]]; then filekey="${FIGMA_FILE_KEY}"; fi

if [[ -z "$filekey" ]]; then
  echo "ERROR Could not resolve file key from URLs/preflight. Set FIGMA_FILE_KEY or export preflight with fileKey."
  exit 2
fi

# STREAM_PATH_NOTE: "awareness" is the hardcoded default stream name.
# If multi-stream support is added, replace "awareness" with the stream name
# from preflight.json (same as resolveStreamFolderName in the generator).
campDir="campaigns/content/$campaign/awareness"
deskJson="$campDir/_sologen/json/$page/desktop.json"
mobJson="$campDir/_sologen/json/$page/mobile.json"
# Sanitise $page for use in flat filenames — replace slashes with hyphens so
# paths like "modals/custom-copay" don't create unintended subdirectories.
pageSafe="${page//\//-}"
isiDeskJson="$campDir/_sologen/json/isi/desktop.json"
isiMobJson="$campDir/_sologen/json/isi/mobile.json"
outDir="$campDir/images"
repDir="$campDir/_sologen/reports"
htmlPath="$campDir/index.shtml"
drawerHtmlPath="$campDir/shared/elements/isi-drawer.html"

mkdir -p "$outDir" "$repDir"

# Load friendly asset name map produced by generate-asset-names.mjs (if present).
# Defines ASSETNAME_<safeId> variables used below for friendlier SVG filenames.
asset_names_sh="campaigns/content/${campaign}/awareness/_sologen/json/asset-names.sh"
[[ -f "$asset_names_sh" ]] && source "$asset_names_sh"

if [[ ! -s "$deskJson" ]]; then echo "ERROR Missing or empty: $deskJson"; exit 3; fi
if [[ ! -s "$mobJson" ]]; then echo "ERROR Missing or empty: $mobJson"; exit 3; fi

tmpIds="$(mktemp)"
tmpRank="$(mktemp)"
tmpUrls="$(mktemp)"

# Stable manifest location (kept for inspection + source control if desired)
tmpMap="$repDir/exportables.$campaign.$pageSafe.svg.json"

cleanup() { rm -f "$tmpIds" "$tmpRank" "$tmpUrls"; }
trap cleanup EXIT

jsonArgs=("$deskJson" "$mobJson")
[[ -s "$isiDeskJson" ]] && jsonArgs+=("$isiDeskJson")
[[ -s "$isiMobJson" ]] && jsonArgs+=("$isiMobJson")

node -e '
const fs = require("fs");

const jsonPaths = process.argv.slice(1);
if(!jsonPaths.length){
  console.error("NODE_ERROR: expected at least 1 json path");
  process.exit(10);
}

function readJson(p){ return JSON.parse(fs.readFileSync(p,"utf8")); }

function eachRootDocs(j){
  const docs = [];
  if(j && j.nodes && typeof j.nodes === "object"){
    for(const k of Object.keys(j.nodes)){
      const v = j.nodes[k];
      if(v && v.document && typeof v.document === "object") docs.push(v.document);
    }
  } else if(j && j.document && typeof j.document === "object"){
    docs.push(j.document);
  } else if(j && typeof j === "object"){
    docs.push(j);
  }
  return docs;
}

function hasSvgExportSettings(n){
  const ex = n.exportSettings;
  if(!Array.isArray(ex) || ex.length === 0) return false;
  return ex.some(s => s && String(s.format||"").toUpperCase() === "SVG");
}

// Walk the tree while tracking whether any ancestor was already marked exportable.
// If both a parent and child are exportable, keep only the highest exportable node.
function walk(n, fn, ancestorExportable){
  if(!n || typeof n !== "object") return;
  const selfExportable = hasSvgExportSettings(n);
  fn(n, ancestorExportable, selfExportable);
  const kids = Array.isArray(n.children) ? n.children : [];
  const nextAncestor = ancestorExportable || selfExportable;
  for(const c of kids) walk(c, fn, nextAncestor);
}

const rankById = new Map();

function collect(doc, sourceRank){
  walk(doc, (n, ancestorExportable, selfExportable) => {
    if(!(selfExportable && !ancestorExportable && n.id)) return;
    const id = String(n.id);
    const prev = rankById.get(id);
    if(prev == null || sourceRank < prev) rankById.set(id, sourceRank);
  }, false);
}

for (const p of jsonPaths){
  const j = readJson(p);
  const isDesktop = /desktop\.json$/i.test(p);
  const isMobile = /mobile\.json$/i.test(p);
  const isIsi = /\/assets\/json\/isi\//i.test(p);
  const rank = isIsi ? 3 : (isDesktop ? 1 : (isMobile ? 2 : 4));
  for(const doc of eachRootDocs(j)){
    collect(doc, rank);
  }
}

[...rankById.entries()]
  .sort((a,b)=>a[0].localeCompare(b[0]))
  .forEach(([id, rank]) => process.stdout.write(id + "\t" + rank + "\n"));
' "${jsonArgs[@]}" > "$tmpRank"

cut -f1 "$tmpRank" > "$tmpIds"

idCount="$(wc -l < "$tmpIds" | tr -d ' ')"
if [[ "$idCount" == "0" ]]; then
  echo "No exportSettings SVG nodes found in $deskJson / $mobJson"
  exit 0
fi

idsCsv="$(paste -sd, "$tmpIds")"

imgsJson="$repDir/exportables.$campaign.$pageSafe.svg.json"
curl -sS -H "X-Figma-Token: $FIGMA_TOKEN" \
  "https://api.figma.com/v1/images/$filekey?ids=$idsCsv&format=svg" \
  -o "$imgsJson"

node -e '
const fs = require("fs");
const imgs = JSON.parse(fs.readFileSync(process.argv[1],"utf8"));
const map = (imgs && imgs.images) ? imgs.images : {};
const out = [];
for(const [id,url] of Object.entries(map)){
  if(url) out.push({ id, url });
}
out.sort((a,b)=>a.id.localeCompare(b.id));
fs.writeFileSync(process.argv[2], JSON.stringify({ count: out.length, images: out }, null, 2));
for(const it of out){
  process.stdout.write(it.id + "\t" + it.url + "\n");
}
' "$imgsJson" "$tmpMap" > "$tmpUrls"

pairCount="$(wc -l < "$tmpUrls" | tr -d ' ')"
if [[ "$pairCount" == "0" ]]; then
  echo "ERROR No downloadable SVG URLs returned from Figma."
  echo "See: $imgsJson"
  exit 4
fi

typeset -A seenSvgHash
typeset -A idRank
typeset -A safeIdRank
typeset -A htmlSvgRef
typeset -A runSvgCandidate

while IFS=$'\t' read -r rid rrank; do
  [[ -n "$rid" && -n "$rrank" ]] || continue
  idRank[$rid]="$rrank"
  safeRid="${rid//[:\/]/-}"
  prevSafeRank="${safeIdRank[$safeRid]-}"
  if [[ -z "$prevSafeRank" || "$rrank" -lt "$prevSafeRank" ]]; then
    safeIdRank[$safeRid]="$rrank"
  fi
done < "$tmpRank"

for refPath in "$htmlPath" "$drawerHtmlPath"; do
if [[ -s "$refPath" ]]; then
  while IFS= read -r safeId; do
    [[ -n "$safeId" ]] || continue
    htmlSvgRef[$safeId]=1
  done < <(node -e '
const fs = require("fs");
const html = fs.readFileSync(process.argv[1], "utf8");
const reSvg = /media\/images\/([A-Za-z0-9_;-]+)\.svg\b/g;
const seen = new Set();
let m;
while((m = reSvg.exec(html))){
  const safeId = String(m[1] || "");
  if(!safeId || seen.has(safeId)) continue;
  seen.add(safeId);
  process.stdout.write(safeId + "\n");
}
' "$refPath")
fi
done

uniqueCount=0
prunedCount=0
while IFS=$'\t' read -r id url; do
  [[ -n "$id" && -n "$url" ]] || continue
  safeId="${id//[:\/]/-}"
  # Use friendly name from asset-names.sh if available; fall back to safeId.svg
  varname="ASSETNAME_${id//[^a-zA-Z0-9]/_}"
  filename="${(P)varname:-${safeId}.svg}"
  runSvgCandidate[$safeId]=1
  tmpSvg="$(mktemp)"
  curl -sSL -o "$tmpSvg" "$url"
  svgHash="$(shasum -a 256 "$tmpSvg" | awk '{print $1}')"

  existingId="${seenSvgHash[$svgHash]-}"
  if [[ -z "$existingId" ]]; then
    mv "$tmpSvg" "$outDir/$filename"
    seenSvgHash[$svgHash]="$id"
    uniqueCount=$((uniqueCount + 1))
    continue
  fi

  existingSafe="${existingId//[:\/]/-}"
  existingVarname="ASSETNAME_${existingId//[^a-zA-Z0-9]/_}"
  existingFilename="${(P)existingVarname:-${existingSafe}.svg}"
  if [[ "$filename" == "$existingFilename" ]]; then
    rm -f "$tmpSvg"
  else
    if [[ -f "$outDir/$existingFilename" ]]; then
      cp "$outDir/$existingFilename" "$outDir/$filename"
      rm -f "$tmpSvg"
    else
      mv "$tmpSvg" "$outDir/$filename"
    fi
  fi
done < "$tmpUrls"

if [[ "${SG_PRUNE_UNREFERENCED_SVGS:-0}" == "1" && "${#htmlSvgRef[@]}" -gt 0 ]]; then
  for safeId in "${(@k)runSvgCandidate}"; do
    candidateRank="${safeIdRank[$safeId]-99}"
    if (( candidateRank >= 3 )); then
      continue
    fi
    # Reconstruct friendly filename for this safeId (Figma IDs never contain "-", so - → _ is safe)
    pruneVarname="ASSETNAME_${safeId//[^a-zA-Z0-9]/_}"
    pruneFilename="${(P)pruneVarname:-${safeId}.svg}"
    if [[ -f "$outDir/$pruneFilename" && -z "${htmlSvgRef[$safeId]-}" ]]; then
      rm -f "$outDir/$pruneFilename"
      prunedCount=$((prunedCount + 1))
    fi
  done
fi

echo "Downloaded $uniqueCount SVG exportables to $outDir (from $pairCount id-url pairs)"
if [[ "${SG_PRUNE_UNREFERENCED_SVGS:-0}" == "1" ]]; then
  echo "Pruned unreferenced SVGs: $prunedCount"
else
  echo "Unreferenced SVG pruning disabled (set SG_PRUNE_UNREFERENCED_SVGS=1 to enable)."
fi
echo "Manifest: $tmpMap"
echo "API response: $imgsJson"
