'use client'

import { useState, useEffect, useTransition } from 'react'
import {
  DndContext, DragEndEvent, DragStartEvent, DragOverlay,
  KeyboardSensor, PointerSensor, useSensor, useSensors, closestCenter,
} from '@dnd-kit/core'
import { sortableKeyboardCoordinates, arrayMove } from '@dnd-kit/sortable'
import { toast } from 'sonner'
import { SplitPane } from '@/components/split-pane/split-pane'
import { SprintBacklogLeft, SprintBacklogRight } from './sprint-backlog'
import type { SprintStory, PbiWithStories, ProductMember } from './sprint-backlog'
import { TaskList } from './task-list'
import type { Task } from './task-list'
import { useSprintStore } from '@/stores/sprint-store'
import {
  addStoryToSprintAction,
  removeStoryFromSprintAction,
  reorderSprintStoriesAction,
} from '@/actions/sprints'

interface SprintBoardClientProps {
  productId: string
  sprintId: string
  stories: SprintStory[]
  pbisWithStories: PbiWithStories[]
  sprintStoryIdList: string[]
  tasksByStory: Record<string, Task[]>
  isDemo: boolean
  currentUserId: string
  members: ProductMember[]
}

export function SprintBoardClient({
  productId,
  sprintId,
  stories,
  pbisWithStories,
  sprintStoryIdList,
  tasksByStory,
  isDemo,
  currentUserId,
  members,
}: SprintBoardClientProps) {
  const [sprintStories, setSprintStories] = useState<SprintStory[]>(stories)
  const [sprintStoryIds, setSprintStoryIds] = useState<Set<string>>(() => new Set(sprintStoryIdList))
  const [selectedStoryId, setSelectedStoryId] = useState<string | null>(null)
  const {
    sprintStoryOrder,
    initSprint,
    addStoryToSprint,
    removeStoryFromSprint,
    reorderSprintStories,
    rollbackSprint,
  } = useSprintStore()
  const [activeDragStory, setActiveDragStory] = useState<SprintStory | null>(null)
  const [, startTransition] = useTransition()

  useEffect(() => {
    initSprint(sprintId, stories.map(s => s.id))
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [sprintId])

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

  function handleDragStart(event: DragStartEvent) {
    const id = event.active.id.toString()
    if (id.startsWith('pb:')) {
      const story = pbisWithStories.flatMap(p => p.stories).find(s => s.id === id.slice(3))
      setActiveDragStory(story ?? null)
    }
  }

  function handleDragEnd(event: DragEndEvent) {
    setActiveDragStory(null)
    const { active, over } = event
    if (!over) return

    const activeId = active.id.toString()
    const overId = over.id.toString()
    const order = sprintStoryOrder[sprintId] ?? sprintStories.map(s => s.id)

    // Drag from left (product backlog) → add to sprint (middle)
    if (activeId.startsWith('pb:')) {
      const storyId = activeId.slice(3)
      const droppingOnSprint =
        overId === 'sprint-zone' ||
        (!overId.startsWith('pb:') && overId !== 'backlog-zone')
      if (droppingOnSprint && !sprintStoryIds.has(storyId)) {
        const storyData = pbisWithStories.flatMap(p => p.stories).find(s => s.id === storyId)
        if (!storyData) return
        setSprintStoryIds(prev => new Set([...prev, storyId]))
        setSprintStories(prev => [...prev, storyData])
        addStoryToSprint(sprintId, storyId)
        startTransition(async () => {
          const result = await addStoryToSprintAction(sprintId, storyId)
          if (!result.success) {
            setSprintStoryIds(prev => { const n = new Set(prev); n.delete(storyId); return n })
            setSprintStories(prev => prev.filter(s => s.id !== storyId))
            removeStoryFromSprint(sprintId, storyId)
            toast.error(result.error ?? 'Toevoegen mislukt')
          }
        })
      }
      return
    }

    // Drag from middle (sprint backlog) → left (product backlog) → remove
    if (overId === 'backlog-zone') {
      const storyData = sprintStories.find(s => s.id === activeId)
      setSprintStoryIds(prev => { const n = new Set(prev); n.delete(activeId); return n })
      setSprintStories(prev => prev.filter(s => s.id !== activeId))
      removeStoryFromSprint(sprintId, activeId)
      if (selectedStoryId === activeId) setSelectedStoryId(null)
      startTransition(async () => {
        const result = await removeStoryFromSprintAction(activeId)
        if (!result.success) {
          if (storyData) {
            setSprintStoryIds(prev => new Set([...prev, activeId]))
            setSprintStories(prev => [...prev, storyData])
          }
          addStoryToSprint(sprintId, activeId)
          toast.error('Verwijderen mislukt')
        }
      })
      return
    }

    // Reorder within sprint (middle panel)
    if (activeId !== overId && !activeId.startsWith('pb:')) {
      const prevOrder = [...order]
      const newOrder = order.includes(overId)
        ? arrayMove([...order], order.indexOf(activeId), order.indexOf(overId))
        : [...order.filter(id => id !== activeId), activeId]

      reorderSprintStories(sprintId, newOrder)
      startTransition(async () => {
        const result = await reorderSprintStoriesAction(sprintId, newOrder)
        if (!result.success) {
          rollbackSprint(sprintId, prevOrder)
          toast.error('Volgorde opslaan mislukt')
        }
      })
    }
  }

  function handleAdd(storyId: string) {
    if (sprintStoryIds.has(storyId)) return
    const storyData = pbisWithStories.flatMap(p => p.stories).find(s => s.id === storyId)
    if (!storyData) return
    setSprintStoryIds(prev => new Set([...prev, storyId]))
    setSprintStories(prev => [...prev, storyData])
    addStoryToSprint(sprintId, storyId)
    startTransition(async () => {
      const result = await addStoryToSprintAction(sprintId, storyId)
      if (!result.success) {
        setSprintStoryIds(prev => { const n = new Set(prev); n.delete(storyId); return n })
        setSprintStories(prev => prev.filter(s => s.id !== storyId))
        removeStoryFromSprint(sprintId, storyId)
        toast.error(result.error ?? 'Toevoegen mislukt')
      }
    })
  }

  function handleAssigneeChange(storyId: string, assigneeId: string | null, assigneeUsername: string | null) {
    setSprintStories(prev =>
      prev.map(s => s.id === storyId ? { ...s, assignee_id: assigneeId, assignee_username: assigneeUsername } : s)
    )
  }

  function handleRemove(storyId: string) {
    const storyData = sprintStories.find(s => s.id === storyId)
    setSprintStoryIds(prev => { const n = new Set(prev); n.delete(storyId); return n })
    setSprintStories(prev => prev.filter(s => s.id !== storyId))
    removeStoryFromSprint(sprintId, storyId)
    if (selectedStoryId === storyId) setSelectedStoryId(null)
    startTransition(async () => {
      const result = await removeStoryFromSprintAction(storyId)
      if (!result.success) {
        if (storyData) {
          setSprintStoryIds(prev => new Set([...prev, storyId]))
          setSprintStories(prev => [...prev, storyData])
        }
        addStoryToSprint(sprintId, storyId)
        toast.error('Verwijderen mislukt')
      }
    })
  }

  const selectedTasks = selectedStoryId ? (tasksByStory[selectedStoryId] ?? []) : []

  return (
    <DndContext
      id="sprint-board"
      sensors={sensors}
      collisionDetection={closestCenter}
      onDragStart={handleDragStart}
      onDragEnd={handleDragEnd}
    >
      <SplitPane
        cookieKey={`sprint-${productId}`}
        defaultSplit={[28, 35, 37]}
        tabLabels={['Backlog', 'Sprint', 'Taken']}
        panes={[
          <SprintBacklogRight
            key="backlog"
            pbisWithStories={pbisWithStories}
            sprintStoryIds={sprintStoryIds}
            isDemo={isDemo}
            onAdd={handleAdd}
          />,
          <SprintBacklogLeft
            key="sprint"
            sprintId={sprintId}
            stories={sprintStories}
            isDemo={isDemo}
            onRemove={handleRemove}
            onSelect={setSelectedStoryId}
            selectedStoryId={selectedStoryId}
            currentUserId={currentUserId}
            productId={productId}
            members={members}
            onAssigneeChange={handleAssigneeChange}
          />,
          selectedStoryId ? (
            <TaskList
              key="tasks"
              storyId={selectedStoryId}
              storyCode={stories.find(s => s.id === selectedStoryId)?.code ?? null}
              sprintId={sprintId}
              productId={productId}
              tasks={selectedTasks}
              isDemo={isDemo}
            />
          ) : (
            <div key="tasks-empty" className="flex items-center justify-center h-full">
              <p className="text-sm text-muted-foreground">Selecteer een story om de taken te bekijken.</p>
            </div>
          ),
        ]}
      />
      <DragOverlay>
        {activeDragStory && (
          <div className="flex items-center gap-3 px-6 py-2 bg-popover border border-primary rounded shadow-lg text-sm opacity-95 w-72">
            <span className="text-muted-foreground select-none">⠿</span>
            <span className="truncate flex-1">{activeDragStory.title}</span>
          </div>
        )}
      </DragOverlay>
    </DndContext>
  )
}
