import * as React from 'react'
import { ChevronLeft, ChevronRight } from 'lucide-react'
import { cn } from '../lib/cn'
import { Button } from '../primitives/button'
import { Select } from '../primitives/select'

/**
 * Cursor-based pagination controls for DataTable.
 *
 * Desktop (≥768px): "Showing X–Y of Z" label + [← Prev] page-counter [Next →]
 *   + Per-page select (20 / 50 / 100).
 * Mobile (<768px): single [Load more] button that appends rows (handled by the
 *   parent via onPageChange). An IntersectionObserver sentinel triggers
 *   auto-load at the list bottom.
 *
 * API contract consumed by backing list endpoints:
 *   Request:  GET /…?cursor=<base64 {id, created_at}>&limit=20|50|100
 *   Response: { data: T[]; meta: { total: number; next_cursor: string | null;
 *               prev_cursor: string | null; has_next: boolean; has_prev: boolean } }
 *   Cursor:   base64(JSON.stringify({ id, created_at }))
 *   Server:   WHERE (created_at, id) < (cursor.created_at, cursor.id) for next
 *             WHERE (created_at, id) > (cursor.created_at, cursor.id) for prev
 *   Stable under concurrent inserts (keyset, not offset).
 *
 * perPage is persisted in localStorage under `table:{storageKey}:perPage`.
 * Filter state resets cursor to page 1 (callers clear cursor on filter change).
 */

export interface DataTablePagination {
  total: number
  nextCursor: string | null
  prevCursor: string | null
  /** Current per-page value — callers initialize from localStorage. */
  perPage: number
  onPageChange: (cursor: string | null, direction: 'next' | 'prev') => void
  onPerPageChange: (perPage: number) => void
  /** localStorage key prefix, e.g. "invoices" → stored as "table:invoices:perPage". */
  storageKey?: string
}

const PER_PAGE_OPTIONS = [
  { value: '20', label: '20' },
  { value: '50', label: '50' },
  { value: '100', label: '100' },
]

export interface PaginationControlsProps {
  pagination: DataTablePagination
  /** Current page number (1-based, display-only — no arbitrary jumps). */
  currentPage: number
  className?: string
}

export function PaginationControls({ pagination, currentPage, className }: PaginationControlsProps) {
  const {
    total,
    nextCursor,
    prevCursor,
    perPage,
    onPageChange,
    onPerPageChange,
    storageKey,
  } = pagination

  const sentinelRef = React.useRef<HTMLDivElement>(null)
  const [isMobile, setIsMobile] = React.useState(false)

  // Detect mobile breakpoint via matchMedia
  React.useEffect(() => {
    const mq = window.matchMedia('(max-width: 767px)')
    const update = () => setIsMobile(mq.matches)
    update()
    mq.addEventListener('change', update)
    return () => mq.removeEventListener('change', update)
  }, [])

  // IntersectionObserver scroll-sentinel for mobile auto-load-more
  React.useEffect(() => {
    if (!isMobile || !nextCursor) return
    const sentinel = sentinelRef.current
    if (!sentinel) return
    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0]?.isIntersecting && nextCursor) {
          onPageChange(nextCursor, 'next')
        }
      },
      { threshold: 0.1 },
    )
    observer.observe(sentinel)
    return () => observer.disconnect()
  }, [isMobile, nextCursor, onPageChange])

  // Persist perPage to localStorage on change
  const handlePerPageChange = (value: string) => {
    const n = parseInt(value, 10)
    if (storageKey) {
      try {
        localStorage.setItem(`table:${storageKey}:perPage`, value)
      } catch {
        // localStorage unavailable (private mode, full, etc.) — continue silently
      }
    }
    onPerPageChange(n)
  }

  // Compute "Showing X–Y of Z"
  const firstRow = total === 0 ? 0 : (currentPage - 1) * perPage + 1
  const lastRow = Math.min(currentPage * perPage, total)
  const canPrev = prevCursor !== null
  const canNext = nextCursor !== null

  if (isMobile) {
    return (
      <div className={cn('flex flex-col items-center gap-4', className)}>
        {nextCursor ? (
          <Button
            variant="outline"
            size="sm"
            onClick={() => onPageChange(nextCursor, 'next')}
          >
            Load more
          </Button>
        ) : null}
        {/* Scroll sentinel — invisible; triggers observer when visible */}
        <div ref={sentinelRef} aria-hidden="true" style={{ height: '1px' }} />
      </div>
    )
  }

  return (
    <div
      className={cn(
        'flex items-center justify-between gap-4 pt-2 text-body-2 text-ink-soft',
        className,
      )}
    >
      {/* Left: row count */}
      <span>
        {total === 0
          ? 'No results'
          : `Showing ${firstRow}–${lastRow} of ${total}`}
      </span>

      {/* Right: Prev / page counter / Next + Per page */}
      <div className="flex items-center gap-4">
        <nav aria-label="Pagination" className="flex items-center gap-2">
          <button
            type="button"
            onClick={() => canPrev && onPageChange(prevCursor, 'prev')}
            disabled={!canPrev}
            aria-label="Previous page"
            className="inline-flex h-8 items-center justify-center gap-1 rounded px-2 text-ink hover:bg-hover disabled:opacity-50 disabled:pointer-events-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-border"
          >
            <ChevronLeft className="h-4 w-4 rtl:rotate-180" aria-hidden="true" />
            <span>Prev</span>
          </button>

          {/* Page counter — display-only; cursor pagination has no jump-to-page */}
          <span
            className="inline-flex h-8 min-w-8 items-center justify-center rounded px-2 text-body-2 bg-accent text-ink-on-accent"
            aria-current="page"
            aria-label={`Page ${currentPage}`}
          >
            {currentPage}
          </span>

          <button
            type="button"
            onClick={() => canNext && onPageChange(nextCursor, 'next')}
            disabled={!canNext}
            aria-label="Next page"
            className="inline-flex h-8 items-center justify-center gap-1 rounded px-2 text-ink hover:bg-hover disabled:opacity-50 disabled:pointer-events-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-border"
          >
            <span>Next</span>
            <ChevronRight className="h-4 w-4 rtl:rotate-180" aria-hidden="true" />
          </button>
        </nav>

        <div className="flex items-center gap-2">
          <span className="text-body-2 text-ink-soft">Per page</span>
          <Select
            options={PER_PAGE_OPTIONS}
            value={String(perPage)}
            onValueChange={(v) => handlePerPageChange(v)}
            aria-label="Rows per page"
          />
        </div>
      </div>
    </div>
  )
}

/**
 * Read the persisted perPage for a given storage key, falling back to 20.
 * Call this in the module component to initialize pagination state.
 */
export function readPerPage(storageKey: string, fallback: 20 | 50 | 100 = 20): number {
  try {
    const stored = localStorage.getItem(`table:${storageKey}:perPage`)
    const n = stored ? parseInt(stored, 10) : fallback
    if (n === 20 || n === 50 || n === 100) return n
  } catch {
    // localStorage unavailable
  }
  return fallback
}
