'use client'

import { useState, useTransition, useEffect } from 'react'
import {
  DndContext,
  DragEndEvent,
  DragOverlay,
  DragStartEvent,
  KeyboardSensor,
  PointerSensor,
  useSensor,
  useSensors,
  closestCenter,
} from '@dnd-kit/core'
import {
  SortableContext,
  useSortable,
  verticalListSortingStrategy,
  arrayMove,
  sortableKeyboardCoordinates,
} from '@dnd-kit/sortable'
import { CSS } from '@dnd-kit/utilities'
import { toast } from 'sonner'
import { CheckSquare, Square } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import {
  BacklogFilterPopover,
  PRIORITY_LABELS,
  type SortDir,
} from '@/components/shared/backlog-filter-popover'
import { useShallow } from 'zustand/react/shallow'
import { readLocalStoragePref } from '@/lib/use-local-storage-pref'
import { useProductWorkspaceStore } from '@/stores/product-workspace/store'
import { selectVisiblePbis } from '@/stores/product-workspace/selectors'
import type { BacklogPbi as WorkspacePbi } from '@/stores/product-workspace/types'
import { deletePbiAction } from '@/actions/pbis'
import { reorderPbisAction, updatePbiPriorityAction } from '@/actions/stories'
import { cn } from '@/lib/utils'
import { debugProps } from '@/lib/debug'
import { PbiDialog, type PbiDialogState } from './pbi-dialog'
import { BacklogCard } from './backlog-card'
import { EmptyPanel } from './empty-panel'
import { NewSprintDialog } from '@/components/sprint/new-sprint-dialog'
import { DemoTooltip } from '@/components/shared/demo-tooltip'
import { PRIORITY_COLORS } from '@/components/shared/priority-select'
import { PBI_STATUS_LABELS, PBI_STATUS_COLORS } from '@/components/shared/pbi-status-select'
import type { PbiStatusApi } from '@/lib/task-status'

type SortMode = 'priority' | 'code' | 'date'

const SORT_OPTIONS: Array<{ value: SortMode; label: string }> = [
  { value: 'priority', label: 'Prioriteit' },
  { value: 'code', label: 'Code' },
  { value: 'date', label: 'Datum' },
]

type PbiStatusFilter = PbiStatusApi | 'all'

const STATUS_OPTIONS: Array<{ value: PbiStatusFilter; label: string }> = [
  { value: 'all', label: 'Alle' },
  { value: 'ready', label: 'Klaar' },
  { value: 'blocked', label: 'Geblokkeerd' },
  { value: 'done', label: 'Afgerond' },
]

interface Pbi {
  id: string
  code: string | null
  title: string
  priority: number
  description?: string | null
  created_at: Date
  status: PbiStatusApi
}

interface PbiListProps {
  productId: string
  isDemo: boolean
}

// --- Sortable PBI row ---
function SortablePbiRow({
  pbi,
  isSelected,
  isDemo,
  selectionMode,
  isChecked,
  onSelect,
  onToggleCheck,
  onEdit,
  onDelete,
}: {
  pbi: Pbi
  isSelected: boolean
  isDemo: boolean
  selectionMode: boolean
  isChecked: boolean
  onSelect: () => void
  onToggleCheck: () => void
  onEdit: () => void
  onDelete: () => void
}) {
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
    id: pbi.id,
    disabled: selectionMode,
  })

  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
  }

  if (selectionMode) {
    return (
      <BacklogCard
        ref={setNodeRef}
        style={style}
        title={pbi.title}
        code={pbi.code}
        priority={pbi.priority}
        isSelected={isChecked}
        role="button"
        tabIndex={0}
        aria-pressed={isChecked}
        onClick={onToggleCheck}
        onKeyDown={(e: React.KeyboardEvent) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onToggleCheck() } }}
        badge={
          <Badge className={cn('text-xs font-normal', PBI_STATUS_COLORS[pbi.status])}>
            {PBI_STATUS_LABELS[pbi.status]}
          </Badge>
        }
        actions={
          <div
            className="inline-flex items-center justify-center min-h-7 min-w-7 text-muted-foreground"
            aria-hidden="true"
          >
            {isChecked ? <CheckSquare size={18} className="text-primary" /> : <Square size={18} />}
          </div>
        }
      />
    )
  }

  return (
    <BacklogCard
      ref={setNodeRef}
      style={style}
      {...attributes}
      {...listeners}
      title={pbi.title}
      code={pbi.code}
      priority={pbi.priority}
      isSelected={isSelected}
      isDragging={isDragging}
      role="button"
      tabIndex={0}
      aria-pressed={isSelected}
      onClick={onSelect}
      onKeyDown={(e: React.KeyboardEvent) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onSelect() } }}
      badge={
        <Badge className={cn('text-xs font-normal', PBI_STATUS_COLORS[pbi.status])}>
          {PBI_STATUS_LABELS[pbi.status]}
        </Badge>
      }
      actions={
        <div className="flex items-center gap-1">
          <DemoTooltip show={isDemo}>
            <button
              onClick={(e) => { e.stopPropagation(); if (!isDemo) onEdit() }}
              className="inline-flex items-center justify-center min-h-7 min-w-7 border border-border rounded text-xs text-muted-foreground hover:text-foreground hover:bg-surface-container transition-colors disabled:opacity-40 disabled:cursor-not-allowed"
              aria-label="Bewerk PBI"
              disabled={isDemo}
            >
              ✎
            </button>
          </DemoTooltip>
          <DemoTooltip show={isDemo}>
            <button
              onClick={(e) => { e.stopPropagation(); if (!isDemo) onDelete() }}
              className="inline-flex items-center justify-center min-h-7 min-w-7 text-muted-foreground hover:text-error text-base leading-none disabled:opacity-40 disabled:cursor-not-allowed"
              aria-label="Verwijder PBI"
              disabled={isDemo}
            >
              ×
            </button>
          </DemoTooltip>
        </div>
      }
    />
  )
}

// --- Main component ---
// PBI-74 / T-849: leest pbis + actieve selectie uit workspace-store via
// useShallow-selector. DnD-mutaties via applyOptimisticMutation/rollback/settle.
export function PbiList({ productId, isDemo }: PbiListProps) {
  // selectVisiblePbis is gesorteerd op priority/sort_order; useShallow
  // voorkomt re-render op ongerelateerde store-mutaties (G2).
  const pbis = useProductWorkspaceStore(useShallow(selectVisiblePbis)) as WorkspacePbi[]
  const selectedPbiId = useProductWorkspaceStore((s) => s.context.activePbiId)
  const [filterPriority, setFilterPriority] = useState<number | 'all'>('all')
  const [filterStatus, setFilterStatus] = useState<PbiStatusFilter>('all')
  const [sortMode, setSortMode] = useState<SortMode>('priority')
  const [sortDir, setSortDir] = useState<SortDir>('asc')
  const [filterPopoverOpen, setFilterPopoverOpen] = useState(false)
  const [prefsLoaded, setPrefsLoaded] = useState(false)
  const [dialogState, setDialogState] = useState<PbiDialogState | null>(null)
  const [activeDragId, setActiveDragId] = useState<string | null>(null)
  const [selectionMode, setSelectionMode] = useState(false)
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())
  const [newSprintOpen, setNewSprintOpen] = useState(false)
  const [, startTransition] = useTransition()

  function exitSelection() {
    setSelectionMode(false)
    setSelectedIds(new Set())
  }

  function toggleCheck(id: string) {
    setSelectedIds(prev => {
      const next = new Set(prev)
      if (next.has(id)) next.delete(id)
      else next.add(id)
      return next
    })
  }

  // Hydrate prefs post-mount; SSR + first client render use defaults so no
  // hydration mismatch. Users with saved == default see no change; others see
  // one filter update right after hydration.
  useEffect(() => {
    /* eslint-disable react-hooks/set-state-in-effect */
    setSortMode(readLocalStoragePref<SortMode>(
      'scrum4me:pbi_sort',
      (raw) => (raw === 'priority' || raw === 'code' || raw === 'date') ? raw : null,
      'priority',
    ))
    setFilterPriority(readLocalStoragePref<number | 'all'>(
      'scrum4me:pbi_filter_priority',
      (raw) => {
        if (raw === 'all') return 'all'
        const n = parseInt(raw, 10)
        return Number.isInteger(n) && n >= 1 && n <= 4 ? n : null
      },
      'all',
    ))
    setFilterStatus(readLocalStoragePref<PbiStatusFilter>(
      'scrum4me:pbi_filter_status',
      (raw) => (raw === 'ready' || raw === 'blocked' || raw === 'done' || raw === 'all') ? raw : null,
      'all',
    ))
    setSortDir(readLocalStoragePref<SortDir>(
      'scrum4me:pbi_sort_dir',
      (raw) => (raw === 'asc' || raw === 'desc') ? raw : null,
      'asc',
    ))
    setPrefsLoaded(true)
    /* eslint-enable react-hooks/set-state-in-effect */
  }, [])

  useEffect(() => { if (prefsLoaded) localStorage.setItem('scrum4me:pbi_sort', sortMode) }, [sortMode, prefsLoaded])
  useEffect(() => { if (prefsLoaded) localStorage.setItem('scrum4me:pbi_filter_priority', String(filterPriority)) }, [filterPriority, prefsLoaded])
  useEffect(() => { if (prefsLoaded) localStorage.setItem('scrum4me:pbi_filter_status', filterStatus) }, [filterStatus, prefsLoaded])
  useEffect(() => { if (prefsLoaded) localStorage.setItem('scrum4me:pbi_sort_dir', sortDir) }, [sortDir, prefsLoaded])

  // pbis komen al gesorteerd binnen via selectVisiblePbis (priority + sort_order).
  // Geen aparte order/priority maps meer — workspace-store entities zijn de waarheid.
  const pbiMap = Object.fromEntries(pbis.map(p => [p.id, p]))
  const orderedPbis = pbis

  const base = orderedPbis.filter(p => {
    if (filterPriority !== 'all' && p.priority !== filterPriority) return false
    if (filterStatus !== 'all' && p.status !== filterStatus) return false
    return true
  })

  const activeFilterCount =
    (filterPriority !== 'all' ? 1 : 0) +
    (filterStatus !== 'all' ? 1 : 0) +
    (sortMode !== 'priority' ? 1 : 0) +
    (sortDir !== 'asc' ? 1 : 0)

  const filtered = [...base].sort((a, b) => {
    let cmp = 0
    if (sortMode === 'code') {
      cmp = (a.code ?? '').localeCompare(b.code ?? '', 'nl', { numeric: true })
    } else if (sortMode === 'date') {
      cmp = new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
    } else {
      cmp = a.priority !== b.priority ? a.priority - b.priority : 0
    }
    return sortDir === 'desc' ? -cmp : cmp
  })

  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
    useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
  )

  function handleDragStart(event: DragStartEvent) {
    setActiveDragId(event.active.id as string)
  }

  function handleDragEnd(event: DragEndEvent) {
    setActiveDragId(null)
    const { active, over } = event
    if (!over || active.id === over.id) return

    const activePbi = pbiMap[active.id as string]
    const overPbi = pbiMap[over.id as string]
    if (!activePbi || !overPbi) return

    const store = useProductWorkspaceStore.getState()
    const prevOrder = [...store.relations.pbiIds]
    const oldIndex = prevOrder.indexOf(active.id as string)
    const newIndex = prevOrder.indexOf(over.id as string)
    if (oldIndex === -1 || newIndex === -1) return
    const newOrder = arrayMove([...prevOrder], oldIndex, newIndex)

    // Snapshot rollback-info en pas optimistisch toe.
    const orderMutationId = store.applyOptimisticMutation({
      kind: 'pbi-order',
      prevPbiIds: prevOrder,
    })
    useProductWorkspaceStore.setState((s) => {
      s.relations.pbiIds = newOrder
    })

    const priorityChanged = activePbi.priority !== overPbi.priority
    let priorityMutationId: string | null = null
    if (priorityChanged) {
      priorityMutationId = store.applyOptimisticMutation({
        kind: 'entity-patch',
        entity: 'pbi',
        id: active.id as string,
        prev: store.entities.pbisById[active.id as string],
      })
      useProductWorkspaceStore.setState((s) => {
        const pbi = s.entities.pbisById[active.id as string]
        if (pbi) pbi.priority = overPbi.priority
      })
    }

    startTransition(async () => {
      const settle = () => {
        const st = useProductWorkspaceStore.getState()
        if (priorityMutationId) st.settleMutation(priorityMutationId)
        st.settleMutation(orderMutationId)
      }
      const rollback = (msg: string) => {
        const st = useProductWorkspaceStore.getState()
        if (priorityMutationId) st.rollbackMutation(priorityMutationId)
        st.rollbackMutation(orderMutationId)
        toast.error(msg)
      }

      if (priorityChanged) {
        const result = await updatePbiPriorityAction(active.id as string, overPbi.priority, productId)
        if (result.success) settle()
        else rollback('Prioriteit opslaan mislukt')
      } else {
        const result = await reorderPbisAction(productId, newOrder)
        if (result.success) settle()
        else rollback('Volgorde opslaan mislukt')
      }
    })
  }

  function handleDelete(id: string) {
    startTransition(async () => {
      await deletePbiAction(id)
      if (selectedPbiId === id) {
        useProductWorkspaceStore.getState().setActivePbi(null)
      }
    })
  }

  const activePbi = activeDragId ? pbiMap[activeDragId] : null

  return (
    <div className="flex flex-col h-full" {...debugProps('pbi-list', 'PbiList', 'components/backlog/pbi-list.tsx')}>
      <div className="flex items-center justify-end gap-2 px-4 py-2 border-b border-border bg-surface-container-low shrink-0" {...debugProps('pbi-list__header')}>
        {filterPriority !== 'all' && (
          <button
            onClick={() => setFilterPriority('all')}
            className="flex items-center gap-1 text-xs text-primary hover:underline"
            aria-label="Wis prioriteitsfilter"
          >
            <Badge className={cn('text-xs', PRIORITY_COLORS[filterPriority])}>
              {PRIORITY_LABELS[filterPriority]}
            </Badge>
            <span>×</span>
          </button>
        )}
        {filterStatus !== 'all' && (
          <button
            onClick={() => setFilterStatus('all')}
            className="flex items-center gap-1 text-xs text-primary hover:underline"
            aria-label="Wis statusfilter"
          >
            <Badge className={cn('text-xs', PBI_STATUS_COLORS[filterStatus])}>
              {PBI_STATUS_LABELS[filterStatus]}
            </Badge>
            <span>×</span>
          </button>
        )}
        <BacklogFilterPopover
          open={filterPopoverOpen}
          onOpenChange={setFilterPopoverOpen}
          filterPriority={filterPriority}
          onFilterPriorityChange={setFilterPriority}
          filterStatus={filterStatus}
          onFilterStatusChange={setFilterStatus}
          statusOptions={STATUS_OPTIONS}
          sort={sortMode}
          onSortChange={setSortMode}
          sortDir={sortDir}
          onSortDirChange={setSortDir}
          sortOptions={SORT_OPTIONS}
          activeFilterCount={activeFilterCount}
          resetDisabled={activeFilterCount === 0}
          onReset={() => {
            setFilterPriority('all')
            setFilterStatus('all')
            setSortMode('priority')
            setSortDir('asc')
          }}
        />
        <DemoTooltip show={isDemo}>
          <Button
            size="sm"
            variant={selectionMode ? 'default' : 'outline'}
            className="h-7 text-xs"
            disabled={isDemo}
            onClick={() => {
              if (isDemo) return
              if (selectionMode) exitSelection()
              else setSelectionMode(true)
            }}
          >
            {selectionMode ? 'Selecteren stoppen' : "Selecteer PBI's"}
          </Button>
        </DemoTooltip>
        <DemoTooltip show={isDemo}>
          <Button
            size="sm"
            className="h-7 text-xs"
            disabled={isDemo || selectionMode}
            onClick={() => !isDemo && setDialogState({ mode: 'create', productId, defaultPriority: 2 })}
          >
            + PBI
          </Button>
        </DemoTooltip>
      </div>

      <div className="flex-1 overflow-y-auto">
        {pbis.length === 0 ? (
          <EmptyPanel
            message="Nog geen PBI's aangemaakt."
            action={{ label: 'Maak je eerste PBI aan', onClick: () => setDialogState({ mode: 'create', productId, defaultPriority: 2 }), disabled: isDemo }}
          />
        ) : (
          <DndContext
            id="pbi-list"
            sensors={sensors}
            collisionDetection={closestCenter}
            onDragStart={handleDragStart}
            onDragEnd={handleDragEnd}
          >
            <SortableContext
              items={filtered.map(p => p.id)}
              strategy={verticalListSortingStrategy}
            >
              <div className="p-3 flex flex-col gap-2" {...debugProps('pbi-list__items')}>
                {filtered.map(pbi => (
                  <SortablePbiRow
                    key={pbi.id}
                    pbi={pbi}
                    isSelected={selectedPbiId === pbi.id}
                    isDemo={isDemo}
                    selectionMode={selectionMode}
                    isChecked={selectedIds.has(pbi.id)}
                    onSelect={() => useProductWorkspaceStore.getState().setActivePbi(pbi.id)}
                    onToggleCheck={() => toggleCheck(pbi.id)}
                    onEdit={() => setDialogState({ mode: 'edit', productId, pbi })}
                    onDelete={() => handleDelete(pbi.id)}
                  />
                ))}
              </div>
            </SortableContext>

            <DragOverlay>
              {activePbi && (
                <BacklogCard
                  title={activePbi.title}
                  priority={activePbi.priority}
                  className="border-primary shadow-xl opacity-90"
                />
              )}
            </DragOverlay>
          </DndContext>
        )}
      </div>

      {selectionMode && (
        <div className="border-t border-border bg-surface-container px-4 py-2 flex items-center justify-between gap-2 shrink-0">
          <span className="text-sm text-foreground">
            {selectedIds.size} geselecteerd
          </span>
          <div className="flex items-center gap-2">
            <Button
              size="sm"
              variant="ghost"
              className="h-7 text-xs"
              onClick={exitSelection}
            >
              Annuleer
            </Button>
            <Button
              size="sm"
              className="h-7 text-xs"
              disabled={selectedIds.size === 0}
              onClick={() => setNewSprintOpen(true)}
            >
              Nieuwe sprint
            </Button>
          </div>
        </div>
      )}

      <PbiDialog
        state={dialogState}
        onClose={() => setDialogState(null)}
        isDemo={isDemo}
      />

      <NewSprintDialog
        open={newSprintOpen}
        productId={productId}
        pbiIds={Array.from(selectedIds)}
        onOpenChange={(open) => {
          setNewSprintOpen(open)
          if (!open) {
            // Sluit selectie bij geslaagde aanmaak; bij annuleren laat de selectie staan
          }
        }}
        onCreated={() => {
          setNewSprintOpen(false)
          exitSelection()
        }}
      />
    </div>
  )
}
