'use client'

import { useState, 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 { useShallow } from 'zustand/react/shallow'
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 { useSprintWorkspaceStore } from '@/stores/sprint-workspace/store'
import { selectStoriesForActiveSprint } from '@/stores/sprint-workspace/selectors'
import type { SprintWorkspaceStory } from '@/stores/sprint-workspace/types'
import {
  addStoryToSprintAction,
  removeStoryFromSprintAction,
  reorderSprintStoriesAction,
} from '@/actions/sprints'
import { debugProps } from '@/lib/debug'

interface SprintBoardClientProps {
  productId: string
  sprintId: string
  pbisWithStories: PbiWithStories[]
  isDemo: boolean
  currentUserId: string
  members: ProductMember[]
}

function toWorkspaceStory(story: SprintStory, sprintId: string): SprintWorkspaceStory {
  return {
    id: story.id,
    code: story.code,
    title: story.title,
    description: story.description,
    acceptance_criteria: story.acceptance_criteria,
    priority: story.priority,
    sort_order: story.sort_order,
    status: story.status,
    pbi_id: story.pbi_id,
    sprint_id: sprintId,
    created_at: story.created_at,
    taskCount: story.taskCount,
    doneCount: story.doneCount,
    assignee_id: story.assignee_id,
    assignee_username: story.assignee_username,
  }
}

export function SprintBoardClient({
  productId,
  sprintId,
  pbisWithStories,
  isDemo,
  currentUserId,
  members,
}: SprintBoardClientProps) {
  const sprintStories = useSprintWorkspaceStore(
    useShallow((s) => selectStoriesForActiveSprint(s) as SprintStory[]),
  )
  const selectedStoryId = useSprintWorkspaceStore((s) => s.context.activeStoryId)
  const sprintStoryIds = new Set(sprintStories.map(s => s.id))
  const [activeDragStory, setActiveDragStory] = useState<SprintStory | null>(null)
  const [, startTransition] = useTransition()

  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()

    // Drag from product backlog (left) → 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) handleAdd(storyId, storyData)
      }
      return
    }

    // Drag from sprint (middle) → product backlog (left) → remove
    if (overId === 'backlog-zone') {
      handleRemove(activeId)
      return
    }

    // Reorder within sprint
    if (activeId !== overId && !activeId.startsWith('pb:')) {
      handleReorder(activeId, overId)
    }
  }

  function handleAdd(storyId: string, storyData: SprintStory) {
    if (sprintStoryIds.has(storyId)) return

    const store = useSprintWorkspaceStore.getState()
    const prevStory = store.entities.storiesById[storyId]
    const prevSprintStoryIds = [...(store.relations.storyIdsBySprint[sprintId] ?? [])]

    useSprintWorkspaceStore.setState((s) => {
      s.entities.storiesById[storyId] = toWorkspaceStory(storyData, sprintId)
      const list = s.relations.storyIdsBySprint[sprintId] ?? []
      if (!list.includes(storyId)) list.push(storyId)
      s.relations.storyIdsBySprint[sprintId] = list
    })

    startTransition(async () => {
      const result = await addStoryToSprintAction(sprintId, storyId)
      if (!result.success) {
        useSprintWorkspaceStore.setState((s) => {
          if (prevStory === undefined) {
            delete s.entities.storiesById[storyId]
          } else {
            s.entities.storiesById[storyId] = prevStory
          }
          s.relations.storyIdsBySprint[sprintId] = prevSprintStoryIds
        })
        toast.error(result.error ?? 'Toevoegen mislukt')
      }
    })
  }

  function handleRemove(storyId: string) {
    const store = useSprintWorkspaceStore.getState()
    const prevStory = store.entities.storiesById[storyId]
    const prevSprintStoryIds = [...(store.relations.storyIdsBySprint[sprintId] ?? [])]

    useSprintWorkspaceStore.setState((s) => {
      const list = s.relations.storyIdsBySprint[sprintId]
      if (list) {
        s.relations.storyIdsBySprint[sprintId] = list.filter((id) => id !== storyId)
      }
      const story = s.entities.storiesById[storyId]
      if (story) story.sprint_id = null
    })

    if (selectedStoryId === storyId) {
      useSprintWorkspaceStore.getState().setActiveStory(null)
    }

    startTransition(async () => {
      const result = await removeStoryFromSprintAction(storyId)
      if (!result.success) {
        useSprintWorkspaceStore.setState((s) => {
          if (prevStory) s.entities.storiesById[storyId] = prevStory
          s.relations.storyIdsBySprint[sprintId] = prevSprintStoryIds
        })
        toast.error('Verwijderen mislukt')
      }
    })
  }

  function handleReorder(activeId: string, overId: string) {
    const store = useSprintWorkspaceStore.getState()
    const order = store.relations.storyIdsBySprint[sprintId] ?? []
    const prevOrder = [...order]
    const newOrder = order.includes(overId)
      ? arrayMove([...order], order.indexOf(activeId), order.indexOf(overId))
      : [...order.filter(id => id !== activeId), activeId]

    const mutationId = store.applyOptimisticMutation({
      kind: 'sprint-story-order',
      sprintId,
      prevStoryIds: prevOrder,
    })
    useSprintWorkspaceStore.setState((s) => {
      s.relations.storyIdsBySprint[sprintId] = newOrder
    })

    startTransition(async () => {
      const result = await reorderSprintStoriesAction(sprintId, newOrder)
      const st = useSprintWorkspaceStore.getState()
      if (result.success) {
        st.settleMutation(mutationId)
      } else {
        st.rollbackMutation(mutationId)
        toast.error('Volgorde opslaan mislukt')
      }
    })
  }

  function handleAssigneeChange(storyId: string, assigneeId: string | null, assigneeUsername: string | null) {
    useSprintWorkspaceStore.setState((s) => {
      const story = s.entities.storiesById[storyId]
      if (story) {
        story.assignee_id = assigneeId
        story.assignee_username = assigneeUsername
      }
    })
  }

  return (
    <div {...debugProps('sprint-board-client')} className="contents">
    <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}
            productId={productId}
            onAdd={(storyId) => {
              const storyData = pbisWithStories.flatMap(p => p.stories).find(s => s.id === storyId)
              if (storyData) handleAdd(storyId, storyData)
            }}
          />,
          <SprintBacklogLeft
            key="sprint"
            sprintId={sprintId}
            isDemo={isDemo}
            onRemove={handleRemove}
            onSelect={(storyId) => useSprintWorkspaceStore.getState().setActiveStory(storyId)}
            selectedStoryId={selectedStoryId}
            currentUserId={currentUserId}
            productId={productId}
            members={members}
            onAssigneeChange={handleAssigneeChange}
          />,
          selectedStoryId ? (
            <TaskList
              key="tasks"
              sprintId={sprintId}
              productId={productId}
              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" data-debug-id="sprint-board-client__drag-overlay">
            <span className="text-muted-foreground select-none">⠿</span>
            <span className="truncate flex-1">{activeDragStory.title}</span>
          </div>
        )}
      </DragOverlay>
    </DndContext>
    </div>
  )
}
