/**
 * ServerDataTable
 *
 * A fully server-side-driven DataTable component.
 * It does NOT use TanStack/React-Table — state lives entirely in URL params
 * and is communicated upward via the `onParamsChange` callback, keeping the
 * component framework-agnostic (works with Inertia, React Router, etc.).
 *
 * Features:
 *  - Debounced global search
 *  - Sortable column headers (asc / desc toggle)
 *  - Show / hide columns (client-side only — no round-trip)
 *  - Page-size selector
 *  - Advanced numeric pagination with ellipsis
 */

import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { cn, getPageNumbers } from '../../lib/utils'
import {
  type PaginationProfileKey,
  getPaginationProfile,
  PAGINATION_PROFILES,
} from './pagination-profiles'
import { Button } from '../ui/button'
import { ComboboxDropdown } from '../combobox-dropdown'
import {
  DropdownMenu,
  DropdownMenuCheckboxItem,
  DropdownMenuContent,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from '../ui/dropdown-menu'
import { Input } from '../ui/input'
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '../ui/table'

// ---------------------------------------------------------------------------
// Public Types
// ---------------------------------------------------------------------------

/** Laravel paginator response (resource or paginate()) */
export interface PaginateMeta {
  current_page: number
  last_page: number
  per_page: number
  total: number
  /** First item number on this page; null when result is empty */
  from: number | null
  /** Last item number on this page; null when result is empty */
  to: number | null
}

export interface ServerPaginatedData<T> extends PaginateMeta {
  data: T[]
}

/**
 * Column definition for ServerDataTable.
 *
 * `render` receives the entire row object and should return a ReactNode.
 * When omitted the raw value of `row[key]` is rendered as a string.
 */
export interface ServerColumnDef<T> {
  /** Unique key matching a property on T (or any string for rendered columns). */
  key: string
  /** Header label. */
  label: string
  /** Pass `true` to show sort icons and allow the user to sort by this column. */
  sortable?: boolean
  /** Applied to each `<td>` in this column. */
  className?: string
  /** Applied to the `<th>` for this column. */
  headerClassName?: string
  /** Start hidden in the toggle-columns panel. */
  defaultHidden?: boolean
  /** Custom cell renderer. Receives the full row. */
  render?: (row: T) => React.ReactNode
}

/** Active query parameters — mirrors typical Laravel paginator URL shape. */
export interface ServerDataTableParams {
  page?: number
  per_page?: number
  search?: string
  sort?: string
  direction?: 'asc' | 'desc'
  /** Any extra filters you want to persist alongside datatable params. */
  [key: string]: string | number | undefined
}

export interface ServerDataTableProps<T> {
  /** Paginated data from the server (Laravel paginate() or simplePaginate()). */
  data: ServerPaginatedData<T>
  /** Column definitions. */
  columns: ServerColumnDef<T>[]
  /** Current active params (usually derived from the URL / Inertia page props). */
  params: ServerDataTableParams
  /**
   * Called whenever the user changes page, page size, search, or sort.
   * The consumer is responsible for navigating / reloading with these params.
   *
   * @example (with Inertia)
   * onParamsChange={(p) => router.get(route('module.index'), p, { preserveState: true })}
   */
  onParamsChange: (params: ServerDataTableParams) => void
  /** Show a search box in the toolbar. Default: `true`. */
  searchable?: boolean
  /** Placeholder for the search input. */
  searchPlaceholder?: string
  /** Available page-size options. Default: `[10, 25, 50, 100]`. */
  pageSizes?: number[]
  /** Pagination profile key. When omitted, auto-detected from current path. */
  paginationProfile?: PaginationProfileKey
  /** Extra class names for the root wrapper. */
  className?: string
  /** Milliseconds to debounce search input. Default: `400`. */
  searchDebounce?: number
  /** Text shown when the table has no rows. */
  emptyText?: string
  /** Visual appearance preset. */
  appearance?: 'default' | 'enterprise-compact'
}

type ServerDataTableAppearance = 'default' | 'enterprise-compact'

function getAppearanceClasses(appearance: ServerDataTableAppearance) {
  if (appearance === 'enterprise-compact') {
    return {
      toolbarWrapper: 'mb-0 border-b border-border bg-background px-4 py-3',
      toolbarLayout: 'gap-3',
      toolbarInput: 'h-8 w-full rounded-md border-border bg-background text-xs sm:w-[220px] lg:w-[280px]',
      viewButton: 'ms-auto h-8 rounded-md border-border bg-background text-xs font-medium shadow-none',
      tableWrapper: 'overflow-hidden rounded-none border-0 bg-background',
      headerRow: 'border-b border-border bg-muted/40 hover:bg-muted/40',
      headerCell: 'h-9 px-4 text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground',
      sortButton: 'ms-0 h-7 px-0 text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground hover:text-foreground',
      bodyRow: 'border-b border-border/60 bg-background hover:bg-muted/30',
      bodyCell: 'px-4 py-2.5 text-sm',
      emptyCell: 'h-20 bg-background px-4 text-center text-sm text-muted-foreground',
      paginationWrapper: 'mt-0 border-t border-border bg-background px-4 py-3',
      paginationLayout: 'gap-2',
      paginationInfo: 'text-xs',
      pageSizeLabel: 'hidden text-xs font-medium text-muted-foreground sm:block',
      pageSizeSelect: 'h-8 w-[84px]',
      paginationButton: 'h-8 min-w-8 rounded-md border-border bg-background px-2 text-xs shadow-none',
      pagerIconButton: 'size-8 rounded-md border-border bg-background p-0 shadow-none',
      ellipsis: 'px-1 text-xs text-muted-foreground',
    }
  }

  return {
    toolbarWrapper: 'mb-3',
    toolbarLayout: 'gap-2',
    toolbarInput: 'h-8 w-[150px] bg-background lg:w-[250px]',
    viewButton: 'ms-auto hidden h-8 text-foreground lg:flex',
    tableWrapper: 'rounded-md border bg-background',
    headerRow: 'bg-background',
    headerCell: '',
    sortButton: '-ms-3 h-8 px-2 text-foreground',
    bodyRow: 'bg-background',
    bodyCell: '',
    emptyCell: 'h-24 bg-background text-center text-muted-foreground',
    paginationWrapper: 'mt-3',
    paginationLayout: 'gap-3 px-2',
    paginationInfo: 'text-sm text-muted-foreground dark:text-muted-foreground',
    pageSizeLabel: 'hidden text-sm font-medium text-foreground sm:block',
    pageSizeSelect: 'h-8 w-[90px]',
    paginationButton: 'h-8 min-w-8 px-2 text-foreground',
    pagerIconButton: 'size-8 p-0 text-foreground',
    ellipsis: 'px-1 text-sm text-muted-foreground dark:text-muted-foreground',
  }
}

// Legacy props (endpoint-driven) kept for backward compatibility.
export interface LegacyServerDataTableProps<T = Record<string, unknown>> {
  columns: Array<Record<string, unknown>>
  endpoint: string
  searchPlaceholder?: string
  enableGlobalFilter?: boolean
  enableSorting?: boolean
  enableRowSelection?: boolean
  enableColumnVisibility?: boolean
  initialPageSize?: number
  className?: string
}

// ---------------------------------------------------------------------------
// Internal: SortIcon
// ---------------------------------------------------------------------------

function SortIcon({
  column,
  sort,
  direction,
}: {
  column: string
  sort?: string
  direction?: 'asc' | 'desc'
}) {
  if (sort !== column)
    return (
      <svg
        xmlns='http://www.w3.org/2000/svg'
        className='ms-1.5 h-4 w-4 shrink-0 text-muted-foreground'
        viewBox='0 0 24 24'
        fill='none'
        stroke='currentColor'
        strokeWidth={1.75}
        strokeLinecap='round'
        strokeLinejoin='round'
      >
        <path d='m8 10 4-4 4 4' />
        <path d='m8 14 4 4 4-4' />
      </svg>
    )
  if (direction === 'asc')
    return (
      <svg
        xmlns='http://www.w3.org/2000/svg'
        className='ms-1.5 h-4 w-4 shrink-0 text-foreground'
        viewBox='0 0 24 24'
        fill='none'
        stroke='currentColor'
        strokeWidth={1.75}
        strokeLinecap='round'
        strokeLinejoin='round'
      >
        <path d='m8 10 4-4 4 4' />
      </svg>
    )
  return (
    <svg
      xmlns='http://www.w3.org/2000/svg'
      className='ms-1.5 h-4 w-4 shrink-0 text-foreground'
      viewBox='0 0 24 24'
      fill='none'
      stroke='currentColor'
      strokeWidth={1.75}
      strokeLinecap='round'
      strokeLinejoin='round'
    >
      <path d='m8 14 4 4 4-4' />
    </svg>
  )
}

// ---------------------------------------------------------------------------
// Internal: ServerColumnHeader
// ---------------------------------------------------------------------------

function ServerColumnHeader<T>({
  col,
  params,
  onParamsChange,
  appearance,
}: {
  col: ServerColumnDef<T>
  params: ServerDataTableParams
  onParamsChange: (p: ServerDataTableParams) => void
  appearance: ServerDataTableAppearance
}) {
  const appearanceClasses = getAppearanceClasses(appearance)

  if (!col.sortable) {
    return <span>{col.label}</span>
  }

  const isActive = params.sort === col.key
  const nextDirection: 'asc' | 'desc' | undefined =
    !isActive ? 'asc' : params.direction === 'asc' ? 'desc' : undefined
  const currentSortState =
    !isActive ? 'none' : params.direction === 'asc' ? 'ascending' : 'descending'

  function handleSortCycle() {
    if (!nextDirection) {
      const { sort: _sort, direction: _direction, ...rest } = params
      onParamsChange({ ...rest, page: 1 })
      return
    }

    onParamsChange({ ...params, sort: col.key, direction: nextDirection, page: 1 })
  }

  return (
    <Button
      variant='ghost'
      size='sm'
      className={appearanceClasses.sortButton}
      aria-label={`Sort ${col.label}: ${currentSortState}`}
      onClick={handleSortCycle}
    >
      <span>{col.label}</span>
      <SortIcon column={col.key} sort={params.sort} direction={params.direction} />
    </Button>
  )
}

// ---------------------------------------------------------------------------
// Internal: ServerViewOptions
// ---------------------------------------------------------------------------

function ServerViewOptions<T>({
  columns,
  visibility,
  onToggle,
  appearance,
}: {
  columns: ServerColumnDef<T>[]
  visibility: Record<string, boolean>
  onToggle: (key: string, visible: boolean) => void
  appearance: ServerDataTableAppearance
}) {
  const appearanceClasses = getAppearanceClasses(appearance)

  return (
    <DropdownMenu modal={false}>
      <DropdownMenuTrigger asChild>
        <Button variant='outline' size='sm' className={appearanceClasses.viewButton}>
          <svg xmlns='http://www.w3.org/2000/svg' className='me-2 size-4' viewBox='0 0 15 15' fill='none'>
            <path d='M5 3a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm-2.354.146A3.001 3.001 0 0 1 7.83 4.5H13.5a.5.5 0 0 1 0 1H7.83A3.001 3.001 0 0 1 2.646 4.146zM10 8.5a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm2.354-.354A3.001 3.001 0 0 1 7.17 9.5H1.5a.5.5 0 0 1 0-1h5.67a3.001 3.001 0 0 1 5.184-1.354zM5 12a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm-2.354.146A3.001 3.001 0 0 1 7.83 13.5H13.5a.5.5 0 0 1 0 1H7.83a3.001 3.001 0 0 1-5.184-1.354z' fill='currentColor' fillRule='evenodd' clipRule='evenodd' />
          </svg>
          Kolom
        </Button>
      </DropdownMenuTrigger>
      <DropdownMenuContent align='end' className='w-[180px] text-foreground'>
        <DropdownMenuLabel>Tampilkan kolom</DropdownMenuLabel>
        <DropdownMenuSeparator />
        {columns.map((col) => (
          <DropdownMenuCheckboxItem
            key={col.key}
            className='capitalize text-foreground'
            checked={visibility[col.key] !== false}
            onCheckedChange={(checked) => onToggle(col.key, checked)}
          >
            {col.label}
          </DropdownMenuCheckboxItem>
        ))}
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

// ---------------------------------------------------------------------------
// Internal: ServerToolbar
// ---------------------------------------------------------------------------

function ServerToolbar<T>({
  columns,
  params,
  onParamsChange,
  visibility,
  onToggleVisibility,
  searchable,
  searchPlaceholder,
  searchDebounce,
  appearance,
}: {
  columns: ServerColumnDef<T>[]
  params: ServerDataTableParams
  onParamsChange: (p: ServerDataTableParams) => void
  visibility: Record<string, boolean>
  onToggleVisibility: (key: string, visible: boolean) => void
  searchable: boolean
  searchPlaceholder: string
  searchDebounce: number
  appearance: ServerDataTableAppearance
}) {
  const appearanceClasses = getAppearanceClasses(appearance)
  const [localSearch, setLocalSearch] = useState(params.search ?? '')
  const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)

  // Sync when external params change (e.g. browser back/forward)
  useEffect(() => {
    setLocalSearch(params.search ?? '')
  }, [params.search])

  function handleSearchChange(value: string) {
    setLocalSearch(value)
    if (debounceRef.current) clearTimeout(debounceRef.current)
    debounceRef.current = setTimeout(() => {
      onParamsChange({ ...params, search: value || undefined, page: 1 })
    }, searchDebounce)
  }

  return (
    <div className={cn('flex items-center justify-between', appearanceClasses.toolbarLayout)}>
      <div className='flex flex-1 flex-col-reverse items-start gap-y-2 sm:flex-row sm:items-center sm:space-x-2'>
        {searchable && (
          <Input
            placeholder={searchPlaceholder}
            value={localSearch}
            onChange={(e) => handleSearchChange(e.target.value)}
            className={appearanceClasses.toolbarInput}
          />
        )}
      </div>
      <ServerViewOptions
        columns={columns}
        visibility={visibility}
        onToggle={onToggleVisibility}
        appearance={appearance}
      />
    </div>
  )
}

// ---------------------------------------------------------------------------
// Internal: ServerPagination
// ---------------------------------------------------------------------------

function ServerPagination({
  meta,
  params,
  onParamsChange,
  pageSizes,
  appearance,
}: {
  meta: PaginateMeta
  params: ServerDataTableParams
  onParamsChange: (p: ServerDataTableParams) => void
  pageSizes: number[]
  appearance: ServerDataTableAppearance
}) {
  const appearanceClasses = getAppearanceClasses(appearance)
  const { current_page, last_page, per_page, total, from, to } = meta
  const pageNumbers = getPageNumbers(current_page, last_page)
  const normalizedPageSizes = Array.from(new Set([...pageSizes, per_page]))
    .filter((size) => Number.isFinite(size) && size > 0)
    .sort((a, b) => a - b)

  function goTo(page: number) {
    if (page < 1 || page > last_page) return
    onParamsChange({ ...params, page })
  }

  function changePageSize(size: number) {
    onParamsChange({ ...params, per_page: size, page: 1 })
  }

  return (
    <div className={cn('flex flex-col sm:flex-row sm:items-center sm:justify-between', appearanceClasses.paginationLayout)}>
      {/* Info: showing X–Y of Z */}
      <p className={cn('shrink-0', appearanceClasses.paginationInfo)}>
        {from && to
          ? `Menampilkan ${from}–${to} dari ${total} baris`
          : `${total} baris`}
      </p>

      <div className='flex flex-wrap items-center gap-3'>
        {/* Page size */}
        <div className='flex items-center gap-2'>
          <p className={appearanceClasses.pageSizeLabel}>Baris per halaman</p>
          <ComboboxDropdown
            options={normalizedPageSizes.map((size) => ({
              label: String(size),
              value: String(size),
            }))}
            value={String(per_page)}
            onValueChange={(v) => changePageSize(Number(v))}
            clearable={false}
            searchable={false}
            placeholder='Rows'
            className={appearanceClasses.pageSizeSelect}
          />
        </div>

        {/* Page navigation */}
        <div className='flex items-center gap-1'>
          {/* First */}
          <Button
            variant='outline'
            className={cn(appearanceClasses.pagerIconButton, '@max-md/content:hidden')}
            onClick={() => goTo(1)}
            disabled={current_page === 1}
            aria-label='Go to first page'
          >
            <svg
              xmlns='http://www.w3.org/2000/svg'
              className='h-4 w-4'
              viewBox='0 0 24 24'
              fill='none'
              stroke='currentColor'
              strokeWidth={2}
              strokeLinecap='round'
              strokeLinejoin='round'
            >
              <polyline points='11 17 6 12 11 7' />
              <polyline points='18 17 13 12 18 7' />
            </svg>
          </Button>

          {/* Prev */}
          <Button
            variant='outline'
            className={appearanceClasses.pagerIconButton}
            onClick={() => goTo(current_page - 1)}
            disabled={current_page === 1}
            aria-label='Go to previous page'
          >
            <svg
              xmlns='http://www.w3.org/2000/svg'
              className='h-4 w-4'
              viewBox='0 0 24 24'
              fill='none'
              stroke='currentColor'
              strokeWidth={2}
              strokeLinecap='round'
              strokeLinejoin='round'
            >
              <polyline points='15 18 9 12 15 6' />
            </svg>
          </Button>

          {/* Numbered pages */}
          {pageNumbers.map((p, i) =>
            p === '...' ? (
              <span key={`ellipsis-${i}`} className={appearanceClasses.ellipsis}>
                …
              </span>
            ) : (
              <Button
                key={p}
                variant={current_page === p ? 'default' : 'outline'}
                className={appearanceClasses.paginationButton}
                onClick={() => goTo(p as number)}
              >
                {p}
              </Button>
            )
          )}

          {/* Next */}
          <Button
            variant='outline'
            className={appearanceClasses.pagerIconButton}
            onClick={() => goTo(current_page + 1)}
            disabled={current_page === last_page}
            aria-label='Go to next page'
          >
            <svg
              xmlns='http://www.w3.org/2000/svg'
              className='h-4 w-4'
              viewBox='0 0 24 24'
              fill='none'
              stroke='currentColor'
              strokeWidth={2}
              strokeLinecap='round'
              strokeLinejoin='round'
            >
              <polyline points='9 18 15 12 9 6' />
            </svg>
          </Button>

          {/* Last */}
          <Button
            variant='outline'
            className={cn(appearanceClasses.pagerIconButton, '@max-md/content:hidden')}
            onClick={() => goTo(last_page)}
            disabled={current_page === last_page}
            aria-label='Go to last page'
          >
            <svg
              xmlns='http://www.w3.org/2000/svg'
              className='h-4 w-4'
              viewBox='0 0 24 24'
              fill='none'
              stroke='currentColor'
              strokeWidth={2}
              strokeLinecap='round'
              strokeLinejoin='round'
            >
              <polyline points='13 17 18 12 13 7' />
              <polyline points='6 17 11 12 6 7' />
            </svg>
          </Button>
        </div>
      </div>
    </div>
  )
}

// ---------------------------------------------------------------------------
// Main: ServerDataTable
// ---------------------------------------------------------------------------

export function ServerDataTable<T extends object>({
  ...rawProps
}: ServerDataTableProps<T> | LegacyServerDataTableProps<T>) {
  const isLegacyMode = 'endpoint' in rawProps && !('data' in rawProps)
  const legacyEndpoint = isLegacyMode
    ? (rawProps as LegacyServerDataTableProps<T>).endpoint
    : undefined

  const resolveValue = useCallback((row: Record<string, unknown>, key: string) => {
    const segments = String(key).split('.')
    let cursor: unknown = row
    for (const segment of segments) {
      if (cursor == null || typeof cursor !== 'object') return undefined
      cursor = (cursor as Record<string, unknown>)[segment]
    }
    return cursor
  }, [])

  const adaptLegacyColumns = useCallback(
    (legacyColumns: Array<Record<string, unknown>>): ServerColumnDef<T>[] => {
      return legacyColumns
        .map((col) => {
          const accessorKey = col.accessorKey
          const id = col.id
          const key = String(
            (typeof accessorKey === 'string' && accessorKey) ||
            (typeof id === 'string' && id) ||
            ''
          )
          if (!key) return null

          const header = col.header
          const label = typeof header === 'string' ? header : key
          const sortable = col.enableSorting !== false && typeof accessorKey === 'string'
          const legacyCell = typeof col.cell === 'function' ? col.cell : undefined

          const render = (row: T) => {
            if (!legacyCell) {
              const value = resolveValue(row as Record<string, unknown>, key)
              return (value as React.ReactNode) ?? '—'
            }
            return legacyCell({
              row: {
                original: row,
                getValue: (k: string) =>
                  resolveValue(row as Record<string, unknown>, k),
              },
            } as Record<string, unknown>)
          }

          return {
            key,
            label,
            sortable,
            render,
          } satisfies ServerColumnDef<T>
        })
        .filter(Boolean) as ServerColumnDef<T>[]
    },
    [resolveValue]
  )

  const defaultLegacyProfile = PAGINATION_PROFILES['master-data']
  const legacyPageSize = isLegacyMode
    ? ((rawProps as LegacyServerDataTableProps<T>).initialPageSize ?? defaultLegacyProfile.defaultPerPage)
    : defaultLegacyProfile.defaultPerPage
  const [legacyRows, setLegacyRows] = useState<T[]>([])
  const [legacyMeta, setLegacyMeta] = useState<PaginateMeta>({
    current_page: 1,
    last_page: 1,
    per_page: legacyPageSize,
    total: 0,
    from: null,
    to: null,
  })
  const [legacyLoading, setLegacyLoading] = useState(false)

  const [legacyParams, setLegacyParams] = useState<ServerDataTableParams>({
    page: 1,
    per_page: legacyPageSize,
  })

  useEffect(() => {
    if (!isLegacyMode || !legacyEndpoint) return

    const page = Number(legacyParams.page ?? 1)
    const pageSize = Number(legacyParams.per_page ?? legacyPageSize)
    const search = String(legacyParams.search ?? '')
    const sortBy = typeof legacyParams.sort === 'string' ? legacyParams.sort : ''
    const sortDirection = legacyParams.direction === 'desc' ? 'desc' : 'asc'
    const controller = new AbortController()

    const query = new URLSearchParams({
      page: String(page),
      pageSize: String(pageSize),
      search,
      globalFilter: search,
      sortBy,
      sortDirection,
    })

    setLegacyLoading(true)
    fetch(`${legacyEndpoint}?${query.toString()}`, {
      headers: { Accept: 'application/json' },
      credentials: 'same-origin',
      signal: controller.signal,
    })
      .then(async (response) => {
        if (!response.ok) {
          throw new Error(`Request failed (${response.status})`)
        }
        return response.json()
      })
      .then((payload) => {
        const rows = Array.isArray(payload?.data) ? payload.data : []
        const meta = payload?.meta ?? {}
        const currentPage = Number(meta.page ?? page) || page
        const perPage = Number(meta.pageSize ?? pageSize) || pageSize
        const total = Number(meta.totalCount ?? 0) || 0
        const lastPage = Number(meta.totalPages ?? 1) || 1
        const from = total > 0 ? (currentPage - 1) * perPage + 1 : null
        const to = total > 0 ? Math.min(currentPage * perPage, total) : null

        setLegacyRows(rows as T[])
        setLegacyMeta({
          current_page: currentPage,
          last_page: lastPage,
          per_page: perPage,
          total,
          from,
          to,
        })
      })
      .catch(() => {
        if (controller.signal.aborted) return
        setLegacyRows([])
        setLegacyMeta((prev) => ({
          ...prev,
          total: 0,
          from: null,
          to: null,
        }))
      })
      .finally(() => {
        if (controller.signal.aborted) return
        setLegacyLoading(false)
      })
    return () => {
      controller.abort()
    }
  }, [isLegacyMode, legacyEndpoint, legacyParams, legacyPageSize])

  const props = rawProps as ServerDataTableProps<T>
  const columns = isLegacyMode
    ? adaptLegacyColumns((rawProps as LegacyServerDataTableProps<T>).columns)
    : props.columns
  const data = isLegacyMode
    ? ({ data: legacyRows, ...legacyMeta } as ServerPaginatedData<T>)
    : props.data
  const params = isLegacyMode ? legacyParams : props.params
  const onParamsChange = isLegacyMode ? setLegacyParams : props.onParamsChange
  const searchable = isLegacyMode
    ? ((rawProps as LegacyServerDataTableProps<T>).enableGlobalFilter ?? true)
    : (props.searchable ?? true)
  const searchPlaceholder = isLegacyMode
    ? ((rawProps as LegacyServerDataTableProps<T>).searchPlaceholder ?? 'Search…')
    : (props.searchPlaceholder ?? 'Search…')
  const className = isLegacyMode
    ? (rawProps as LegacyServerDataTableProps<T>).className
    : props.className
  const searchDebounce = isLegacyMode ? 400 : (props.searchDebounce ?? 400)
  const runtimePathname = typeof window !== 'undefined' ? window.location.pathname : ''
  const detectedProfile = getPaginationProfile(runtimePathname)
  const explicitProfile = !isLegacyMode && props.paginationProfile
    ? PAGINATION_PROFILES[props.paginationProfile]
    : detectedProfile
  const pageSizes = isLegacyMode
    ? defaultLegacyProfile.pageSizes
    : (props.pageSizes ?? explicitProfile.pageSizes)
  const emptyText = isLegacyMode
    ? (legacyLoading ? 'Memuat…' : 'Tidak ada data.')
    : (props.emptyText ?? 'Tidak ada data.')
  const appearance = isLegacyMode ? 'default' : (props.appearance ?? 'default')
  const appearanceClasses = getAppearanceClasses(appearance)

  // Column visibility — local state only, no server round-trip
  const [visibility, setVisibility] = useState<Record<string, boolean>>(() =>
    Object.fromEntries(
      columns.map((col) => [col.key, col.defaultHidden ? false : true])
    )
  )

  const visibleColumns = useMemo(
    () => columns.filter((col) => visibility[col.key] !== false),
    [columns, visibility]
  )

  const handleToggleVisibility = useCallback((key: string, visible: boolean) => {
    setVisibility((prev) => ({ ...prev, [key]: visible }))
  }, [])

  const { data: rows = [], ...meta } = data ?? ({ data: [] } as unknown as ServerPaginatedData<T>)
  const normalizedMeta: PaginateMeta = {
    current_page: Number((meta as Partial<PaginateMeta>).current_page ?? params.page ?? 1) || 1,
    last_page: Number((meta as Partial<PaginateMeta>).last_page ?? 1) || 1,
    per_page: Number((meta as Partial<PaginateMeta>).per_page ?? params.per_page ?? explicitProfile.defaultPerPage) || explicitProfile.defaultPerPage,
    total: Number((meta as Partial<PaginateMeta>).total ?? rows.length ?? 0) || 0,
    from: (meta as Partial<PaginateMeta>).from ?? (rows.length > 0 ? 1 : null),
    to: (meta as Partial<PaginateMeta>).to ?? (rows.length > 0 ? rows.length : null),
  }

  const isInactiveRow = (row: T): boolean => {
    const record = row as Record<string, unknown>
    const isActive = record.is_active
    const deletedAt = record.deleted_at
    const status = typeof record.status === 'string' ? record.status.toLowerCase() : null

    return isActive === false || deletedAt != null || status === 'inactive' || status === 'nonaktif'
  }

  return (
    <div className={className}>
      {/* Toolbar */}
      <div className={appearanceClasses.toolbarWrapper}>
        <ServerToolbar
          columns={columns}
          params={params}
          onParamsChange={onParamsChange}
          visibility={visibility}
          onToggleVisibility={handleToggleVisibility}
          searchable={searchable}
          searchPlaceholder={searchPlaceholder}
          searchDebounce={searchDebounce}
          appearance={appearance}
        />
      </div>

      {/* Table */}
      <div className={appearanceClasses.tableWrapper}>
        <Table>
          <TableHeader>
            <TableRow className={appearanceClasses.headerRow}>
              {visibleColumns.map((col) => (
                <TableHead
                  key={col.key}
                  className={cn(appearanceClasses.headerCell, col.headerClassName)}
                >
                  <ServerColumnHeader
                    col={col}
                    params={params}
                    onParamsChange={onParamsChange}
                    appearance={appearance}
                  />
                </TableHead>
              ))}
            </TableRow>
          </TableHeader>
          <TableBody>
            {rows.length === 0 ? (
              <TableRow>
                <TableCell
                  colSpan={visibleColumns.length}
                  className={appearanceClasses.emptyCell}
                >
                  {emptyText}
                </TableCell>
              </TableRow>
            ) : (
              rows.map((row, rowIndex) => (
                <TableRow
                  key={rowIndex}
                  className={cn(
                    appearanceClasses.bodyRow,
                    isInactiveRow(row) && 'bg-rose-50/70 text-rose-900 hover:bg-rose-50/90 dark:bg-rose-950/25 dark:text-rose-200 dark:hover:bg-rose-950/35'
                  )}
                >
                  {visibleColumns.map((col) => (
                    <TableCell
                      key={col.key}
                      className={cn(appearanceClasses.bodyCell, col.className)}
                    >
                      {col.render
                        ? col.render(row)
                        : ((row as Record<string, unknown>)[col.key] as React.ReactNode) ?? '—'}
                    </TableCell>
                  ))}
                </TableRow>
              ))
            )}
          </TableBody>
        </Table>
      </div>

      {/* Pagination */}
      <div className={appearanceClasses.paginationWrapper}>
        <ServerPagination
          meta={normalizedMeta}
          params={params}
          onParamsChange={onParamsChange}
          pageSizes={pageSizes}
          appearance={appearance}
        />
      </div>
    </div>
  )
}
