'use client'

import { useState, useTransition } 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, MinusSquare, 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 { useUserSettingsStore } from '@/stores/user-settings/store'
import { useProductWorkspaceStore } from '@/stores/product-workspace/store'
import {
  selectPbiTriState,
  selectVisiblePbis,
  type PbiTriState,
} 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 { 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
  activeSprintId?: string | null
}

// --- Sortable PBI row ---
function TriStateIcon({ state }: { state: PbiTriState }) {
  if (state === 'full')
    return <CheckSquare size={18} className="text-primary" />
  if (state === 'partial')
    return <MinusSquare size={18} className="text-primary" />
  return <Square size={18} />
}

function SortablePbiRow({
  pbi,
  isSelected,
  isDemo,
  selectionMode,
  triState,
  onSelect,
  onToggleCheck,
  onEdit,
  onDelete,
}: {
  pbi: Pbi
  isSelected: boolean
  isDemo: boolean
  selectionMode: boolean
  triState: PbiTriState
  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={isSelected}
        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={
          <button
            type="button"
            onClick={(e) => {
              e.stopPropagation()
              onToggleCheck()
            }}
            aria-pressed={triState !== 'empty'}
            aria-label={
              triState === 'full'
                ? 'Stories uit sprint halen'
                : 'Stories aan sprint toevoegen'
            }
            className="inline-flex items-center justify-center min-h-7 min-w-7 text-muted-foreground hover:text-foreground rounded transition-colors"
          >
            <TriStateIcon state={triState} />
          </button>
        }
      />
    )
  }

  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, activeSprintId = null }: 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 prefs = useUserSettingsStore(
    useShallow((s) => s.entities.settings.views?.pbiList ?? {}),
  )
  const setPref = useUserSettingsStore((s) => s.setPref)
  const filterPriority = prefs.filterPriority ?? 'all'
  const filterStatus: PbiStatusFilter = prefs.filterStatus ?? 'all'
  const sortMode: SortMode = prefs.sort ?? 'priority'
  const sortDir: SortDir = prefs.sortDir ?? 'asc'
  const setFilterPriority = (v: number | 'all') =>
    void setPref(['views', 'pbiList', 'filterPriority'], v)
  const setFilterStatus = (v: PbiStatusFilter) =>
    void setPref(['views', 'pbiList', 'filterStatus'], v)
  const setSortMode = (v: SortMode) => void setPref(['views', 'pbiList', 'sort'], v)
  const setSortDir = (v: SortDir) => void setPref(['views', 'pbiList', 'sortDir'], v)
  const [filterPopoverOpen, setFilterPopoverOpen] = useState(false)
  const [dialogState, setDialogState] = useState<PbiDialogState | null>(null)
  const [activeDragId, setActiveDragId] = useState<string | null>(null)
  const [, startTransition] = useTransition()

  // PBI-79 / ST-1337+ST-1338: selectionMode is afgeleid uit drie staten:
  // A′ (pendingSprintDraft) → vinkjes muteren de draft via upsertPbiIntent.
  // B (activeSprintId zonder draft) → vinkjes muteren de membership-buffer
  // via toggleStorySprintMembership per child story (bulk).
  // A (geen sprint, geen draft) → geen vinkjes.
  const hasDraft = useUserSettingsStore(
    (s) => !!s.entities.settings.workflow?.pendingSprintDraft?.[productId],
  )
  const upsertPbiIntent = useUserSettingsStore((s) => s.upsertPbiIntent)
  const toggleStorySprintMembership = useProductWorkspaceStore(
    (s) => s.toggleStorySprintMembership,
  )
  const stateBMode = !hasDraft && !!activeSprintId
  const selectionMode = hasDraft || stateBMode

  function togglePbiInDraft(id: string, currentState: PbiTriState) {
    if (hasDraft) {
      // A′: empty/partial → all; full → none.
      const nextIntent = currentState === 'full' ? 'none' : 'all'
      void upsertPbiIntent(productId, id, nextIntent)
      return
    }
    if (stateBMode && activeSprintId) {
      // State B: bulk-toggle alle child-stories naar/uit de pending buffer.
      const store = useProductWorkspaceStore.getState()
      const storyIds = store.relations.storyIdsByPbi[id] ?? []
      const goingFull = currentState !== 'full'
      for (const storyId of storyIds) {
        const story = store.entities.storiesById[storyId]
        if (!story) continue
        const blocked = store.sprintMembership.crossSprintBlocks[storyId]
        if (blocked) continue
        const inSprint = story.sprint_id === activeSprintId
        if (goingFull && !inSprint) {
          toggleStorySprintMembership(storyId, false)
        }
        if (!goingFull && inSprint) {
          toggleStorySprintMembership(storyId, true)
        }
      }
    }
  }

  // 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"
            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 => (
                  <SortablePbiRowWithTriState
                    key={pbi.id}
                    pbi={pbi}
                    isSelected={selectedPbiId === pbi.id}
                    isDemo={isDemo}
                    selectionMode={selectionMode}
                    productId={productId}
                    onSelect={() => useProductWorkspaceStore.getState().setActivePbi(pbi.id)}
                    onToggle={togglePbiInDraft}
                    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>

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

// PBI-79 / ST-1337: wrapper rond SortablePbiRow die zijn tri-state uit de
// workspace-store leest. Subscribed per PBI zodat alleen de relevante rij
// re-rendert bij pbiIntent/storyOverrides-mutaties.
function SortablePbiRowWithTriState({
  pbi,
  isSelected,
  isDemo,
  selectionMode,
  productId,
  onSelect,
  onToggle,
  onEdit,
  onDelete,
}: {
  pbi: Pbi
  isSelected: boolean
  isDemo: boolean
  selectionMode: boolean
  productId: string
  onSelect: () => void
  onToggle: (id: string, currentState: PbiTriState) => void
  onEdit: () => void
  onDelete: () => void
}) {
  // Tri-state uit pendingSprintDraft (state A′) of pbiSummary (state B).
  // Wanneer geen draft: leid af van pbiSummary; wanneer wel: uit pbiIntent.
  const triState = useUserSettingsStore((s) => {
    const draft = s.entities.settings.workflow?.pendingSprintDraft?.[productId]
    if (draft) {
      const intent = draft.pbiIntent[pbi.id] ?? 'none'
      const override = draft.storyOverrides[pbi.id]
      if (intent === 'all') {
        if (override?.remove.length) return 'partial'
        return 'full'
      }
      if (override?.add.length) return 'partial'
      return 'empty'
    }
    return null
  })
  const summaryTriState = useProductWorkspaceStore((s) =>
    selectPbiTriState(s, pbi.id),
  )
  const effectiveTriState: PbiTriState =
    triState ?? (selectionMode ? summaryTriState : 'empty')

  return (
    <SortablePbiRow
      pbi={pbi}
      isSelected={isSelected}
      isDemo={isDemo}
      selectionMode={selectionMode}
      triState={effectiveTriState}
      onSelect={onSelect}
      onToggleCheck={() => onToggle(pbi.id, effectiveTriState)}
      onEdit={onEdit}
      onDelete={onDelete}
    />
  )
}
