/** Shared uPlot styling and sizing helpers. */
import type uPlot from 'uplot';

export const INK_DIM = '#5d6c7d';
export const GRID = '#141a23';
export const FONT = '600 11px Inter, system-ui, sans-serif';

export function axis(overrides: Partial<uPlot.Axis> = {}): uPlot.Axis {
  return {
    stroke: INK_DIM,
    font: FONT,
    labelFont: FONT,
    ticks: { stroke: GRID, width: 1, size: 4 },
    grid: { stroke: GRID, width: 1 },
    gap: 4,
    ...overrides,
  };
}

/** Keep a chart sized to its container without a resize storm. */
export function observeSize(el: HTMLElement, apply: (w: number, h: number) => void): () => void {
  let frame = 0;
  const ro = new ResizeObserver(() => {
    cancelAnimationFrame(frame);
    frame = requestAnimationFrame(() => {
      const rect = el.getBoundingClientRect();
      if (rect.width > 0 && rect.height > 0) apply(Math.round(rect.width), Math.round(rect.height));
    });
  });
  ro.observe(el);
  return () => {
    cancelAnimationFrame(frame);
    ro.disconnect();
  };
}

/**
 * Vertical "you are here" marker, drawn straight onto the canvas after the
 * series. Cheaper and steadier than a series with one point.
 */
export function positionMarker(getX: () => number | null, colour: string): uPlot.Plugin {
  return {
    hooks: {
      draw: (u: uPlot) => {
        const x = getX();
        if (x == null || !Number.isFinite(x)) return;
        const left = u.valToPos(x, 'x', true);
        if (!Number.isFinite(left)) return;
        const ctx = u.ctx;
        const top = u.bbox.top;
        const bottom = u.bbox.top + u.bbox.height;
        ctx.save();
        ctx.beginPath();
        ctx.strokeStyle = colour;
        ctx.lineWidth = Math.max(1, Math.round(devicePixelRatio));
        ctx.moveTo(left, top);
        ctx.lineTo(left, bottom);
        ctx.stroke();
        ctx.beginPath();
        ctx.fillStyle = colour;
        ctx.arc(left, bottom, 4 * devicePixelRatio, 0, Math.PI * 2);
        ctx.fill();
        ctx.restore();
      },
    },
  };
}
