// @wuys/map · renderers/base.js
//
// Contract that every renderer (SVG, Canvas, WebGL) implements.
// Renderers are responsible for: turning state into pixels, hit-testing, and
// reporting performance back to the dev HUD.
//
// Lifecycle: init → patch* → destroy.  Renderers MUST be idempotent on patch.

/**
 * @typedef {Object} Renderer
 * @property {(target: Element, state: Object, opts: Object) => Promise<void>} init
 * @property {(state: Object) => void} patch        — Apply current state to visuals.
 * @property {() => void} destroy
 * @property {(x: number, y: number) => HitResult | null} hitTest
 * @property {(pt: GeoPoint) => ScreenPoint} worldToScreen
 * @property {(pt: ScreenPoint) => GeoPoint} screenToWorld
 * @property {() => Bounds} getViewport
 * @property {(opts?: Object) => Promise<string>} [exportPNG]
 * @property {(opts?: Object) => Promise<string>} [exportSVG]
 */

/** Renderer plugin registry — set at runtime by individual renderer files. */
const REGISTRY = new Map();

export function registerRenderer(id, factory) {
  REGISTRY.set(id, factory);
}

export function createRenderer(id, args) {
  const factory = REGISTRY.get(id);
  if (!factory) {
    throw new Error("[wuys/map] Unknown renderer: " + id + ". Available: " + [...REGISTRY.keys()].join(", "));
  }
  return factory(args);
}

export function listRenderers() { return [...REGISTRY.keys()]; }

/** Auto-pick the best available renderer. */
export function detectBest() {
  if (REGISTRY.has("webgl") && supportsWebGL2()) return "webgl";
  if (REGISTRY.has("canvas")) return "canvas";
  if (REGISTRY.has("svg")) return "svg";
  throw new Error("[wuys/map] No renderer registered");
}

function supportsWebGL2() {
  try {
    const c = document.createElement("canvas");
    return !!c.getContext("webgl2");
  } catch (_) { return false; }
}
