'use client'

import { useState } from 'react'
import {
  DndContext,
  KeyboardSensor,
  PointerSensor,
  pointerWithin,
  useDraggable,
  useDroppable,
  useSensor,
  useSensors,
  type DragEndEvent,
  type DragStartEvent,
} from '@dnd-kit/core'
import { ChevronDown, Copy, GripVertical, PenLine, Plus, Trash2 } from 'lucide-react'
import type { Page } from '../../lib/pages-service.js'
import type { PageTreeRow } from '../../lib/pages-tree.js'
import { PostStatusBadge, SeoScoreIndicator } from '../../components/posts/badges.js'
import { AuthorAvatar } from '../../components/ui/AuthorAvatar.js'
import { Button } from '../../components/ui/Button.js'
import { RowActionButton, RowActions } from '../../components/ui/RowActions.js'

/**
 * Tree-mode table for the Pages list ("Pages (tree version)" design):
 * nested parent/child rows with indentation (24px per level), a 20×20
 * expand chevron that rotates -90° when collapsed, 56px rows, and hover
 * actions (labeled Edit + Add sub-page / Duplicate / Delete icons).
 *
 * When `flattened` is true (search or status filter active) every match
 * renders at depth 0 and expand state is ignored — the caller passes
 * pre-flattened rows, this component just skips the leaf spacers' tree
 * semantics.
 *
 * Drag-reparent: rows can be dragged (grip handle) and dropped onto
 * another row to become its child. There is intentionally no "drop to
 * make top-level" zone — with `parentPageId` cleared, the tree falls back
 * to path-prefix derivation, which would silently re-nest most pages, so
 * un-nesting stays an editor operation. Disabled while flattened.
 */

interface PagesTreeTableProps {
  rows: PageTreeRow[]
  loading: boolean
  error: string | null
  /** true when search/status filters flattened the tree */
  flattened: boolean
  selected: Set<string>
  expanded: Set<string>
  onToggleExpand: (id: string) => void
  onToggleSelect: (id: string) => void
  onToggleAll: (checked: boolean) => void
  onOpen: (page: Page) => void
  onAddSubPage: (page: Page) => void
  onDuplicate: (page: Page) => void
  onDelete: (page: Page) => void
  /** Drop handler: `source` becomes a child of `targetParent`. */
  onReparent: (sourceId: string, targetParentId: string) => void
  /** Validity gate for a drop (cycle/self/no-op checks live in the caller). */
  canReparent: (sourceId: string, targetParentId: string) => boolean
  onRetry: () => void
  onClearFilters: () => void
  onNewPage: () => void
}

const TH_CLASS =
  'px-3 py-2.5 text-left text-[11.5px] font-semibold tracking-[0.4px] uppercase text-[var(--muted)]'

export function PagesTreeTable({
  rows,
  loading,
  error,
  flattened,
  selected,
  expanded,
  onToggleExpand,
  onToggleSelect,
  onToggleAll,
  onOpen,
  onAddSubPage,
  onDuplicate,
  onDelete,
  onReparent,
  canReparent,
  onRetry,
  onClearFilters,
  onNewPage,
}: PagesTreeTableProps) {
  const allSelected = rows.length > 0 && rows.every((r) => selected.has(r.page.id))
  const [draggingId, setDraggingId] = useState<string | null>(null)

  // A small activation distance keeps plain clicks (title, checkbox,
  // chevron) from starting a drag.
  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 6 } }),
    useSensor(KeyboardSensor),
  )

  const handleDragStart = (event: DragStartEvent) => {
    setDraggingId(String(event.active.id))
  }

  const handleDragEnd = (event: DragEndEvent) => {
    setDraggingId(null)
    const sourceId = String(event.active.id)
    const targetId = event.over ? String(event.over.id) : null
    if (!targetId || targetId === sourceId) return
    if (!canReparent(sourceId, targetId)) return
    onReparent(sourceId, targetId)
  }

  return (
    <DndContext
      sensors={sensors}
      collisionDetection={pointerWithin}
      onDragStart={handleDragStart}
      onDragEnd={handleDragEnd}
      onDragCancel={() => setDraggingId(null)}
    >
      <div className="overflow-x-auto">
        <table className="w-full min-w-[800px]" role="table" aria-label="Pages tree">
          <colgroup>
            <col style={{ width: '40px' }} />
            <col />
            <col style={{ width: '130px' }} />
            <col style={{ width: '150px' }} />
            <col style={{ width: '120px' }} />
            <col style={{ width: '115px' }} />
            <col style={{ width: '70px' }} />
            <col style={{ width: '170px' }} />
          </colgroup>
          <thead className="border-b border-[var(--bdr)]">
            <tr>
              <th scope="col" className="px-3 py-2.5 text-left">
                <input
                  type="checkbox"
                  aria-label="Select all visible pages"
                  checked={allSelected}
                  onChange={(e) => onToggleAll(e.target.checked)}
                  className="accent-primary rounded border-[var(--bdr)]"
                />
              </th>
              <th scope="col" className={`${TH_CLASS} min-w-[280px]`}>
                Title
              </th>
              <th scope="col" className={TH_CLASS}>
                Template
              </th>
              <th scope="col" className={TH_CLASS}>
                Author
              </th>
              <th scope="col" className={TH_CLASS}>
                Status
              </th>
              <th scope="col" className={TH_CLASS}>
                Last Modified
              </th>
              <th scope="col" className={TH_CLASS}>
                SEO
              </th>
              <th scope="col" className="px-3 py-2.5 text-right">
                <span className="sr-only">Actions</span>
              </th>
            </tr>
          </thead>
          <tbody>
            {loading && rows.length === 0 && <TreeLoadingRows />}
            {!loading && error && (
              <tr>
                <td colSpan={8} className="px-3 py-12 text-center">
                  <div className="mb-2 text-sm font-medium text-[var(--txt)]">{error}</div>
                  <Button variant="link" size="md" onClick={onRetry}>
                    Try again
                  </Button>
                </td>
              </tr>
            )}
            {!loading && !error && rows.length === 0 && (
              <tr>
                <td colSpan={8} className="px-3 py-16 text-center">
                  <div className="mb-2 text-sm font-medium text-[var(--txt)]">
                    {flattened ? 'No pages match your filters' : 'No pages yet'}
                  </div>
                  <div className="mb-4 text-sm text-[var(--sub)]">
                    {flattened
                      ? 'Try clearing the search or status filter above.'
                      : 'Create your first page to get started.'}
                  </div>
                  {flattened ? (
                    <Button type="button" variant="link" size="md" onClick={onClearFilters}>
                      Clear filters
                    </Button>
                  ) : (
                    <Button
                      type="button"
                      variant="primary"
                      size="sm"
                      className="shadow-sm"
                      onClick={onNewPage}
                      leftIcon={<Plus size={16} aria-hidden />}
                    >
                      New page
                    </Button>
                  )}
                </td>
              </tr>
            )}
            {!loading &&
              !error &&
              rows.map((row) => (
                <TreeRow
                  key={row.page.id}
                  row={row}
                  isSelected={selected.has(row.page.id)}
                  isExpanded={expanded.has(row.page.id)}
                  draggable={!flattened}
                  isDropTarget={
                    draggingId !== null &&
                    draggingId !== row.page.id &&
                    canReparent(draggingId, row.page.id)
                  }
                  onToggleExpand={() => onToggleExpand(row.page.id)}
                  onToggleSelect={() => onToggleSelect(row.page.id)}
                  onOpen={() => onOpen(row.page)}
                  onAddSubPage={() => onAddSubPage(row.page)}
                  onDuplicate={() => onDuplicate(row.page)}
                  onDelete={() => onDelete(row.page)}
                />
              ))}
          </tbody>
        </table>
      </div>
    </DndContext>
  )
}

function TreeRow({
  row,
  isSelected,
  isExpanded,
  draggable,
  isDropTarget,
  onToggleExpand,
  onToggleSelect,
  onOpen,
  onAddSubPage,
  onDuplicate,
  onDelete,
}: {
  row: PageTreeRow
  isSelected: boolean
  isExpanded: boolean
  draggable: boolean
  /** true while another row is being dragged and this row is a valid parent */
  isDropTarget: boolean
  onToggleExpand: () => void
  onToggleSelect: () => void
  onOpen: () => void
  onAddSubPage: () => void
  onDuplicate: () => void
  onDelete: () => void
}) {
  const { page, depth, hasChildren } = row
  const {
    attributes,
    listeners,
    setNodeRef: setDragRef,
    isDragging,
  } = useDraggable({ id: page.id, disabled: !draggable })
  const { setNodeRef: setDropRef, isOver } = useDroppable({
    id: page.id,
    disabled: !draggable || !isDropTarget,
  })

  return (
    <tr
      ref={setDropRef}
      className={`group h-14 border-b border-[var(--bdr)] transition-colors last:border-b-0 hover:bg-[var(--acc-l)] ${
        isSelected ? 'bg-[var(--acc-l)]' : ''
      } ${isDragging ? 'opacity-40' : ''} ${
        isDropTarget && isOver
          ? 'bg-[var(--acc-l)] shadow-[inset_0_0_0_2px_var(--acc)]'
          : isDropTarget
            ? 'shadow-[inset_0_0_0_1px_var(--acc-m)]'
            : ''
      }`}
    >
      <td className="px-3 align-middle">
        <input
          type="checkbox"
          aria-label={`Select "${page.title}"`}
          checked={isSelected}
          onChange={onToggleSelect}
          className="accent-primary rounded border-[var(--bdr)]"
        />
      </td>
      <td className="px-3 align-middle">
        {/* Indentation is data-driven (24px per depth level), so it must be
            an inline style rather than a class. */}
        <div className="flex items-center" style={{ paddingLeft: depth * 24 }}>
          {draggable && (
            <button
              type="button"
              ref={setDragRef}
              {...attributes}
              {...listeners}
              aria-label={`Move "${page.title}" — drag onto another page to nest it there`}
              title="Drag to move under another page"
              className="mr-1 flex h-5 w-5 shrink-0 cursor-grab items-center justify-center rounded-[5px] text-[var(--muted)] opacity-0 transition-opacity duration-[var(--motion-fast)] group-hover:opacity-100 hover:bg-[var(--acc-l)] hover:text-[var(--acc)] focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:outline-none active:cursor-grabbing"
            >
              <GripVertical size={13} aria-hidden />
            </button>
          )}
          {hasChildren ? (
            <button
              type="button"
              aria-expanded={isExpanded}
              aria-label={`${isExpanded ? 'Collapse' : 'Expand'} ${page.title}`}
              onClick={onToggleExpand}
              className="flex h-5 w-5 shrink-0 items-center justify-center rounded-[5px] text-[var(--muted)] transition-colors duration-[var(--motion-fast)] hover:bg-[var(--acc-l)] hover:text-[var(--acc)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:outline-none"
            >
              <ChevronDown
                size={13}
                aria-hidden
                className={`motion-safe:transition-transform motion-safe:duration-150 ${
                  isExpanded ? '' : '-rotate-90'
                }`}
              />
            </button>
          ) : (
            <span className="w-5 shrink-0" aria-hidden />
          )}
          <div className="min-w-0">
            <button
              type="button"
              onClick={onOpen}
              className="block max-w-[280px] truncate text-left text-[13.5px] font-[550] text-[var(--txt)] transition-colors duration-[var(--motion-fast)] hover:text-[var(--acc)]"
            >
              {page.title}
            </button>
            <div className="max-w-[280px] truncate font-mono text-[11.5px] text-[var(--muted)]">
              {page.path}
            </div>
          </div>
        </div>
      </td>
      <td className="px-3 align-middle">
        {page.templateId ? (
          <span className="rounded-[5px] border border-[var(--bdr)] bg-[var(--bg)] px-2 py-0.5 text-[11.5px] whitespace-nowrap text-[var(--sub)]">
            {page.templateId}
          </span>
        ) : (
          <span className="text-[var(--muted)]">—</span>
        )}
      </td>
      <td className="px-3 align-middle">
        <div className="flex items-center gap-[7px]">
          <AuthorAvatar name={page.authorName} size={22} />
          <span className="truncate text-[13px] text-[var(--txt)]">{page.authorName}</span>
        </div>
      </td>
      <td className="px-3 align-middle">
        <PostStatusBadge status={page.status} />
      </td>
      <td className="px-3 align-middle text-[12.5px] text-[var(--sub)] tabular-nums">
        {formatDateShort(page.lastModified)}
      </td>
      <td className="px-3 align-middle">
        <SeoScoreIndicator score={page.seoScore} />
      </td>
      <td className="px-3 align-middle">
        <RowActions>
          <button
            type="button"
            onClick={onOpen}
            className="flex items-center gap-[5px] rounded-[6px] border border-[var(--bdr)] bg-[var(--card)] px-[9px] py-[5px] text-[12px] font-medium whitespace-nowrap text-[var(--txt)] transition-colors duration-[var(--motion-fast)] hover:border-[var(--acc)] hover:bg-[var(--acc-l)] hover:text-[var(--acc)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:outline-none"
          >
            <PenLine size={12} aria-hidden />
            Edit
          </button>
          <RowActionButton
            aria-label={`Add sub-page under "${page.title}"`}
            title="Add sub-page"
            onClick={onAddSubPage}
          >
            <Plus size={12} aria-hidden />
          </RowActionButton>
          <RowActionButton
            aria-label={`Duplicate "${page.title}"`}
            title="Duplicate"
            onClick={onDuplicate}
          >
            <Copy size={12} aria-hidden />
          </RowActionButton>
          <RowActionButton
            aria-label={`Delete "${page.title}"`}
            title={page.isHomepage ? 'The homepage cannot be deleted' : 'Delete'}
            danger
            disabled={page.isHomepage}
            onClick={onDelete}
          >
            <Trash2 size={12} aria-hidden />
          </RowActionButton>
        </RowActions>
      </td>
    </tr>
  )
}

function TreeLoadingRows() {
  return (
    <>
      {Array.from({ length: 8 }).map((_, i) => (
        <tr key={i} className="h-14 border-b border-[var(--bdr)] last:border-b-0">
          {Array.from({ length: 8 }).map((__, j) => (
            <td key={j} className="px-3 align-middle">
              <div className="bg-muted h-4 w-full animate-pulse rounded" />
            </td>
          ))}
        </tr>
      ))}
    </>
  )
}

function formatDateShort(input: string): string {
  const d = new Date(input)
  if (Number.isNaN(d.getTime())) return '—'
  return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' })
}
