import { DOCS_PAGE_GAP_PX } from "./docs-page-layout-constants.ts"
import {
  type DocsGraphicAttrs,
  parseGraphicAttrs,
} from "./docs-graphic-types.ts"

export type PageCoords = {
  pageIndex: number
  pageX: number
  pageY: number
}

/** Graphics rendered on the page overlay layer (not clipped by prose). */
export function usesPageLayer(attrs: DocsGraphicAttrs | Record<string, unknown>): boolean {
  const parsed = "graphicType" in attrs ? (attrs as DocsGraphicAttrs) : parseGraphicAttrs(attrs)
  return (
    parsed.wrap === "behind" ||
    parsed.wrap === "in-front" ||
    parsed.positionMode === "fixed-on-page"
  )
}

export type PageLayerSlot = "behind" | "front"

/** Which page overlay slot should host this graphic. */
export function pageLayerSlot(attrs: DocsGraphicAttrs): PageLayerSlot | null {
  if (!usesPageLayer(attrs)) return null
  if (attrs.wrap === "behind") return "behind"
  return "front"
}

export function pageLayerElementId(slot: PageLayerSlot): string {
  return slot === "behind"
    ? "docs-page-graphic-layer-behind"
    : "docs-page-graphic-layer-front"
}

export function pageTopPx(pageIndex: number, pageHeight: number): number {
  return pageIndex * (pageHeight + DOCS_PAGE_GAP_PX)
}

export function pageIndexFromStackY(stackY: number, pageHeight: number): number {
  if (stackY < 0) return 0
  const stride = pageHeight + DOCS_PAGE_GAP_PX
  return Math.max(0, Math.floor(stackY / stride))
}

export function stackYFromPageCoords(pageIndex: number, pageY: number, pageHeight: number): number {
  return pageTopPx(pageIndex, pageHeight) + pageY
}

/** Convert DOM bbox (viewport px) to page-stack coordinates. */
export function bboxToPageCoords(
  rect: DOMRect,
  stackRect: DOMRect,
  scale: number,
  pageHeight: number
): PageCoords {
  const stackX = (rect.left - stackRect.left) / scale
  const stackY = (rect.top - stackRect.top) / scale
  const pageIndex = pageIndexFromStackY(stackY, pageHeight)
  const pageY = stackY - pageTopPx(pageIndex, pageHeight)
  return {
    pageIndex,
    pageX: Math.round(stackX),
    pageY: Math.round(Math.max(0, pageY)),
  }
}

/**
 * Re-resolve page index after a drag so pageY stays within the page the
 * graphic visually sits on (a drag may cross page boundaries).
 */
export function normalizePageCoords(
  pageIndex: number,
  pageY: number,
  pageHeight: number
): { pageIndex: number; pageY: number } {
  if (pageHeight <= 0) {
    return { pageIndex: Math.max(0, pageIndex), pageY: Math.round(pageY) }
  }
  const stackY = stackYFromPageCoords(Math.max(0, pageIndex), pageY, pageHeight)
  const nextIndex = pageIndexFromStackY(stackY, pageHeight)
  const rawY = stackY - pageTopPx(nextIndex, pageHeight)
  // Clamp into the page band (a drop in the inter-page gap snaps to the page bottom).
  const nextY = Math.min(Math.max(0, Math.round(rawY)), pageHeight)
  return { pageIndex: nextIndex, pageY: nextY }
}

export function pageCoordsToStackStyle(
  pageIndex: number,
  pageX: number,
  pageY: number,
  pageHeight: number
): { left: number; top: number } {
  return {
    left: pageX,
    top: stackYFromPageCoords(pageIndex, pageY, pageHeight),
  }
}
