"use client"

import { useCallback, useEffect, useState } from "react"
import type { Editor } from "@tiptap/react"
import type { DocPageLayout } from "@/lib/drive/doc-page-setup"
import { DOCS_PAGE_GAP_PX } from "@/lib/drive/docs-page-layout-constants"
import {
  docsPageLengthToScreen,
  docsScreenLengthToPage,
  docsZoomToScale,
} from "@/lib/drive/docs-ruler-scale"

export type DocsParagraphIndents = {
  leftPx: number
  firstLinePx: number
  rightPx: number
}

export type DocsRulerSyncState = {
  currentPage: number
  pageTopInViewport: number
  pageHeightScaled: number
  /** Canvas client width — ruler track content area matches this. */
  canvasWidth: number
  /** Scrollbar gutter so ruler track centers like the canvas viewport. */
  canvasScrollbarWidth: number
  canvasScrollLeft: number
  indents: DocsParagraphIndents
}

const DEFAULT_INDENTS = (layout: DocPageLayout): DocsParagraphIndents => ({
  leftPx: layout.marginsPx.left,
  firstLinePx: layout.marginsPx.left,
  rightPx: layout.widthPx - layout.marginsPx.right,
})

function readIndents(
  editor: Editor | null,
  scale: number,
  layout: DocPageLayout
): DocsParagraphIndents {
  const fallback = DEFAULT_INDENTS(layout)
  if (!editor || editor.isDestroyed) return fallback

  const prose = editor.view.dom as HTMLElement | null
  if (!prose) return fallback

  const { from } = editor.state.selection
  const domPos = editor.view.domAtPos(from)
  let el = domPos.node as HTMLElement
  if (el.nodeType === Node.TEXT_NODE) el = el.parentElement ?? el

  const block = el.closest?.(
    "p, h1, h2, h3, h4, li, blockquote, pre, td, th"
  ) as HTMLElement | null
  if (!block || !prose.contains(block)) return fallback

  const pageStack = prose.closest(
    "[data-docs-page-stack]"
  ) as HTMLElement | null
  if (!pageStack) return fallback

  const pageRect = pageStack.getBoundingClientRect()
  const blockRect = block.getBoundingClientRect()
  const leftPx = docsScreenLengthToPage(blockRect.left - pageRect.left, scale)
  const style = getComputedStyle(block)
  const textIndent = parseFloat(style.textIndent) || 0

  return {
    leftPx: Math.max(layout.marginsPx.left, leftPx),
    firstLinePx: Math.max(layout.marginsPx.left, leftPx + textIndent),
    rightPx: layout.widthPx - layout.marginsPx.right,
  }
}

import {
  computePageTopInViewport,
  resolveCurrentPageInViewport,
} from "./docs-ruler-sync-math"

export function useDocsRulerSync({
  canvasRef,
  rulerTrackRef,
  editor,
  pageLayout,
  zoom,
  pageCount,
}: {
  canvasRef: React.RefObject<HTMLDivElement | null>
  rulerTrackRef: React.RefObject<HTMLDivElement | null>
  editor: Editor | null
  pageLayout: DocPageLayout
  zoom: number
  pageCount: number
  narrowViewport: boolean
}) {
  const scale = docsZoomToScale(zoom)
  const pageHeight = pageLayout.heightPx
  const pageHeightScaled = docsPageLengthToScreen(pageHeight, scale)
  const gapScaled = docsPageLengthToScreen(DOCS_PAGE_GAP_PX, scale)
  const pageStride = pageHeightScaled + gapScaled

  const [state, setState] = useState<DocsRulerSyncState>(() => ({
    currentPage: 0,
    pageTopInViewport: 0,
    pageHeightScaled,
    canvasWidth: 0,
    canvasScrollbarWidth: 0,
    canvasScrollLeft: 0,
    indents: DEFAULT_INDENTS(pageLayout),
  }))

  const sync = useCallback(() => {
    const canvas = canvasRef.current
    if (!canvas) return

    const canvasRect = canvas.getBoundingClientRect()
    const stack = canvas.querySelector("[data-docs-page-stack]") as HTMLElement | null

    let pageTopInViewport = 0
    let currentPage = 0

    if (stack) {
      const stackRect = stack.getBoundingClientRect()
      const stackTopInViewport = stackRect.top - canvasRect.top

      currentPage = resolveCurrentPageInViewport(
        stackTopInViewport,
        canvas.clientHeight,
        pageStride,
        pageCount
      )

      pageTopInViewport = computePageTopInViewport(
        stackTopInViewport,
        currentPage,
        pageStride
      )
    }

    setState({
      currentPage,
      pageTopInViewport,
      pageHeightScaled,
      canvasWidth: canvas.clientWidth,
      canvasScrollbarWidth: Math.max(0, canvas.offsetWidth - canvas.clientWidth),
      canvasScrollLeft: canvas.scrollLeft,
      indents: readIndents(editor, scale, pageLayout),
    })
  }, [canvasRef, editor, pageCount, pageHeightScaled, pageLayout, pageStride, scale])

  useEffect(() => {
    sync()
    const canvas = canvasRef.current
    if (!canvas) return

    canvas.addEventListener("scroll", sync, { passive: true })
    const ro = new ResizeObserver(sync)
    ro.observe(canvas)
    const rulerTrack = rulerTrackRef.current
    if (rulerTrack) ro.observe(rulerTrack)

    return () => {
      canvas.removeEventListener("scroll", sync)
      ro.disconnect()
    }
  }, [canvasRef, rulerTrackRef, sync])

  useEffect(() => {
    if (!editor || editor.isDestroyed) return
    const onSelection = () => sync()
    editor.on("selectionUpdate", onSelection)
    editor.on("transaction", onSelection)
    return () => {
      editor.off("selectionUpdate", onSelection)
      editor.off("transaction", onSelection)
    }
  }, [editor, sync])

  useEffect(() => {
    sync()
  }, [pageLayout, zoom, pageCount, sync])

  return state
}
