# Pagination — accessible headless page navigation
#
# Renders page buttons with prev/next and ellipsis gaps.
# Ships zero CSS.
#
# Usage:
#   Pagination page <=> currentPage, total: 100, perPage: 10
#   Pagination page <=> currentPage, total: 500, perPage: 20, siblingCount: 2

export Pagination = component
  @page:: number := 1
  @total:: number := 0
  @perPage:: number := 10
  @siblingCount:: number := 1

  totalPages ~= Math.max(1, Math.ceil(@total / @perPage))
  _ready := false

  _range: (start, fin) ->
    len = fin - start + 1
    Array.from {length: len}, (_, i) -> start + i

  visiblePages ~=
    tp = totalPages
    sibs = @siblingCount
    current = @page

    totalNumbers = sibs * 2 + 5
    return @_range(1, tp) if tp <= totalNumbers

    leftSib  = Math.max(current - sibs, 1)
    rightSib = Math.min(current + sibs, tp)

    showLeftDots  = leftSib > 2
    showRightDots = rightSib < tp - 1

    if not showLeftDots and showRightDots
      leftCount = 3 + 2 * sibs
      leftRange = @_range(1, leftCount)
      return [...leftRange, -1, tp]

    if showLeftDots and not showRightDots
      rightCount = 3 + 2 * sibs
      rightRange = @_range(tp - rightCount + 1, tp)
      return [1, -2, ...rightRange]

    midRange = @_range(leftSib, rightSib)
    [1, -2, ...midRange, -1, tp]

  goto: (pg) ->
    pg = Math.max(1, Math.min(pg, totalPages))
    return if pg is @page
    @page = pg
    @emit 'change', @page

  onKeydown: (e) ->
    switch e.key
      when 'ArrowLeft'
        e.preventDefault()
        @goto(@page - 1)
      when 'ArrowRight'
        e.preventDefault()
        @goto(@page + 1)
      when 'Home'
        e.preventDefault()
        @goto(1)
      when 'End'
        e.preventDefault()
        @goto(totalPages)

  mounted: ->
    _ready = true

  _prevPages = null

  _rebuild: (inner) ->
    frag = document.createDocumentFragment()
    for pg in visiblePages
      if pg < 0
        el = document.createElement 'span'
        el.setAttribute 'data-ellipsis', ''
        el.textContent = '...'
      else
        el = document.createElement 'button'
        el.setAttribute 'aria-label', "Page #{pg}"
        el.setAttribute 'data-page', ''
        el.textContent = "#{pg}"
        el.addEventListener 'click', => @goto(pg)
      frag.appendChild el
    inner.replaceChildren frag
    _prevPages = visiblePages.join ','

  _syncActive: (inner) ->
    for btn in inner.querySelectorAll('[data-page]')
      pg = parseInt btn.textContent
      if pg is @page
        btn.setAttribute 'aria-current', 'page'
        btn.setAttribute 'data-active', ''
      else
        btn.removeAttribute 'aria-current'
        btn.removeAttribute 'data-active'

  ~>
    return unless _ready
    inner = @_nav?.querySelector('[data-pages]')
    return unless inner

    key = visiblePages.join ','
    if key isnt _prevPages
      @_rebuild inner
    @_syncActive inner

  render
    nav ref: "_nav", aria-label: "Pagination", @keydown: @onKeydown
      button $prev: true, aria-label: "Previous page"
        disabled: @page <= 1
        $disabled: (@page <= 1)?!
        @click: (=> @goto(@page - 1))
      . $pages: true
      button $next: true, aria-label: "Next page"
        disabled: @page >= totalPages
        $disabled: (@page >= totalPages)?!
        @click: (=> @goto(@page + 1))
