export type PdfRect = [number, number, number, number];

export interface ParsedPdfAnchor {
  page: number;
  rects: PdfRect[];
}

const PDF_ANCHOR_PREFIX = "pdf:v1:";

export function isPdfAnchor(anchor: string): boolean {
  return anchor.startsWith(PDF_ANCHOR_PREFIX) || anchor.startsWith("pdf:page:");
}

export function parsePageHref(href: string): number | null {
  const match = href.match(/^pdf:page:(\d+)$/);
  if (!match) return null;
  const page = Number(match[1]);
  return Number.isFinite(page) && page > 0 ? page : null;
}

export function serializePdfAnchor(page: number, rects?: PdfRect[]): string {
  const base = `${PDF_ANCHOR_PREFIX}p=${page}`;
  if (!rects?.length) return base;
  return `${base};rects=${encodeURIComponent(JSON.stringify(rects))}`;
}

export function parsePdfAnchor(anchor: string): ParsedPdfAnchor | null {
  if (anchor.startsWith("pdf:page:")) {
    const page = parsePageHref(anchor);
    return page ? { page, rects: [] } : null;
  }
  if (!anchor.startsWith(PDF_ANCHOR_PREFIX)) return null;

  const pageMatch = anchor.match(/p=(\d+)/);
  if (!pageMatch) return null;
  const page = Number(pageMatch[1]);
  if (!Number.isFinite(page) || page < 1) return null;

  const rectsMatch = anchor.match(/rects=([^;]+)/);
  let rects: PdfRect[] = [];
  if (rectsMatch) {
    try {
      const parsed = JSON.parse(decodeURIComponent(rectsMatch[1])) as unknown;
      if (Array.isArray(parsed)) {
        rects = parsed.filter(
          (r): r is PdfRect =>
            Array.isArray(r) &&
            r.length === 4 &&
            r.every((n) => typeof n === "number" && Number.isFinite(n)),
        );
      }
    } catch {
      rects = [];
    }
  }

  return { page, rects };
}

export function rectsFromSelection(
  range: Range,
  pageElement: HTMLElement,
): PdfRect[] {
  const pageRect = pageElement.getBoundingClientRect();
  if (pageRect.width <= 0 || pageRect.height <= 0) return [];

  const rects: PdfRect[] = [];
  for (const clientRect of range.getClientRects()) {
    if (clientRect.width <= 0 || clientRect.height <= 0) continue;
    const x = (clientRect.left - pageRect.left) / pageRect.width;
    const y = (clientRect.top - pageRect.top) / pageRect.height;
    const w = clientRect.width / pageRect.width;
    const h = clientRect.height / pageRect.height;
    rects.push([
      Math.max(0, Math.min(1, x)),
      Math.max(0, Math.min(1, y)),
      Math.max(0, Math.min(1, w)),
      Math.max(0, Math.min(1, h)),
    ]);
  }
  return rects;
}
