'use client'

import { useEffect, useState, useTransition } from 'react'
import {
  DndContext, DragEndEvent, DragOverlay, DragStartEvent,
  PointerSensor, useSensor, useSensors, closestCorners,
} from '@dnd-kit/core'
import { toast } from 'sonner'
import { useSoloStore } from '@/stores/solo-store'
import { taskStatusToApi } from '@/lib/task-status'
import { enqueueAllTodoJobsAction } from '@/actions/claude-jobs'
import { Button } from '@/components/ui/button'
import { DemoTooltip } from '@/components/shared/demo-tooltip'
import { SplitPane } from '@/components/split-pane/split-pane'
import { SoloColumn, type ColumnStatus } from './solo-column'
import { SoloTaskCardOverlay } from './solo-task-card'
import { TaskDetailDialog } from './task-detail-dialog'
import { UnassignedStoriesSheet, type UnassignedStory } from './unassigned-stories-sheet'

export interface SoloTask {
  id: string
  title: string
  description: string | null
  implementation_plan: string | null
  priority: number
  sort_order: number
  status: 'TO_DO' | 'IN_PROGRESS' | 'REVIEW' | 'DONE'
  verify_only: boolean
  story_id: string
  story_code: string | null
  story_title: string
  task_code: string | null
}

export interface SoloBoardProps {
  productId: string
  sprintGoal: string
  tasks: SoloTask[]
  unassignedStories: UnassignedStory[]
  isDemo: boolean
  currentUserId: string
  repoUrl?: string | null
}

const COLUMN_STATUSES: ColumnStatus[] = ['TO_DO', 'IN_PROGRESS', 'DONE']

function getColumnStatus(status: SoloTask['status']): ColumnStatus {
  if (status === 'REVIEW') return 'IN_PROGRESS'
  return status
}

export function SoloBoard({
  productId, sprintGoal, tasks: initialTasks, unassignedStories: initialUnassigned, isDemo, repoUrl,
}: SoloBoardProps) {
  const { tasks, initTasks, optimisticMove, rollback, markPending, clearPending } = useSoloStore()
  const claudeJobsByTaskId = useSoloStore((s) => s.claudeJobsByTaskId)
  const [activeDragId, setActiveDragId] = useState<string | null>(null)
  const [selectedTask, setSelectedTask] = useState<SoloTask | null>(null)
  const [sheetOpen, setSheetOpen] = useState(false)
  const [unassignedStories, setUnassignedStories] = useState(initialUnassigned)
  const [, startTransition] = useTransition()
  const [batchPending, startBatchTransition] = useTransition()

  const taskKey = initialTasks.map(t => t.id).join(',')
  useEffect(() => {
    initTasks(initialTasks)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [taskKey])

  const pointerSensor = useSensor(PointerSensor, { activationConstraint: { distance: 5 } })
  const sensors = useSensors(...(isDemo ? [] : [pointerSensor]))

  const taskList = Object.values(tasks)
  const columnTasks: Record<ColumnStatus, SoloTask[]> = {
    TO_DO: taskList.filter(t => getColumnStatus(t.status) === 'TO_DO'),
    IN_PROGRESS: taskList.filter(t => getColumnStatus(t.status) === 'IN_PROGRESS'),
    DONE: taskList.filter(t => getColumnStatus(t.status) === 'DONE'),
  }

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

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

    const toStatus = over.id as ColumnStatus
    if (!COLUMN_STATUSES.includes(toStatus)) return

    const taskId = active.id as string
    const task = tasks[taskId]
    if (!task) return
    if (getColumnStatus(task.status) === toStatus) return

    const prevStatus = optimisticMove(taskId, toStatus)
    if (!prevStatus) return

    // Onderdruk realtime-echo van onze eigen write — de Postgres-trigger
    // vuurt en die NOTIFY komt zo terug via SSE; zonder pending-marker
    // zou de store nogmaals een set() doen of de optimistic state
    // overschrijven. clearPending na de fetch (succes of fail).
    //
    // We gebruiken bewust een fetch-based Route Handler in plaats van
    // de updateTaskStatusAction Server Action — Server Actions
    // triggeren een full route-tree refresh die de open SSE-stream van
    // /api/realtime/solo zou afkappen, waardoor we elke 5s reconnecten
    // en realtime-events missen.
    markPending(taskId)
    startTransition(async () => {
      try {
        const res = await fetch(`/api/tasks/${taskId}`, {
          method: 'PATCH',
          headers: { 'Content-Type': 'application/json' },
          credentials: 'include',
          body: JSON.stringify({ status: taskStatusToApi(toStatus) }),
        })
        if (!res.ok) {
          rollback(taskId, prevStatus)
          toast.error('Status bijwerken mislukt — taak teruggeplaatst')
        }
      } catch {
        rollback(taskId, prevStatus)
        toast.error('Status bijwerken mislukt — taak teruggeplaatst')
      } finally {
        clearPending(taskId)
      }
    })
  }

  const activeTask = activeDragId ? tasks[activeDragId] : null

  const queueableCount = columnTasks.TO_DO.filter(t => {
    const job = claudeJobsByTaskId[t.id]
    return !job || (job.status !== 'queued' && job.status !== 'claimed' && job.status !== 'running')
  }).length

  function handleStartAll() {
    if (queueableCount === 0) return
    startBatchTransition(async () => {
      const result = await enqueueAllTodoJobsAction(productId)
      if ('error' in result) {
        toast.error(result.error)
      } else if (result.count === 0) {
        toast.info('Geen taken om te starten')
      } else {
        toast.success(`${result.count} ${result.count === 1 ? 'agent' : 'agents'} ingeschakeld`)
      }
    })
  }

  return (
    <div className="flex flex-col h-full p-4 gap-4 min-h-0">
      <div className="flex items-start justify-between gap-4 shrink-0">
        <div className="min-w-0 flex items-center gap-3">
          <DemoTooltip show={isDemo}>
            <Button
              size="sm"
              onClick={handleStartAll}
              disabled={isDemo || batchPending || queueableCount === 0}
            >
              {batchPending ? 'Starten…' : `Start agents (${queueableCount})`}
            </Button>
          </DemoTooltip>
          {sprintGoal && (
            <p className="text-sm text-muted-foreground line-clamp-2 min-w-0">{sprintGoal}</p>
          )}
        </div>
        <button
          className="text-sm text-primary hover:underline whitespace-nowrap shrink-0 disabled:text-muted-foreground disabled:cursor-default"
          disabled={unassignedStories.length === 0}
          onClick={() => setSheetOpen(true)}
        >
          Toon openstaande stories ({unassignedStories.length})
        </button>
      </div>

      <DndContext
        sensors={sensors}
        collisionDetection={closestCorners}
        onDragStart={handleDragStart}
        onDragEnd={handleDragEnd}
      >
        <div className="flex-1 min-h-0">
          <SplitPane
            cookieKey={`solo-${productId}`}
            defaultSplit={[33, 33, 34]}
            tabLabels={['Te doen', 'Bezig', 'Klaar']}
            panes={[
              <SoloColumn
                key="TO_DO"
                status="TO_DO"
                tasks={columnTasks.TO_DO}
                isDemo={isDemo}
                onTaskClick={(t) => setSelectedTask(t)}
              />,
              <SoloColumn
                key="IN_PROGRESS"
                status="IN_PROGRESS"
                tasks={columnTasks.IN_PROGRESS}
                isDemo={isDemo}
                onTaskClick={(t) => setSelectedTask(t)}
              />,
              <SoloColumn
                key="DONE"
                status="DONE"
                tasks={columnTasks.DONE}
                isDemo={isDemo}
                onTaskClick={(t) => setSelectedTask(t)}
              />,
            ]}
          />
        </div>
        <DragOverlay>
          {activeTask && <SoloTaskCardOverlay task={activeTask} />}
        </DragOverlay>
      </DndContext>

      <TaskDetailDialog
        task={selectedTask}
        productId={productId}
        isDemo={isDemo}
        repoUrl={repoUrl}
        onClose={() => setSelectedTask(null)}
      />

      <UnassignedStoriesSheet
        stories={unassignedStories}
        productId={productId}
        isDemo={isDemo}
        open={sheetOpen}
        onOpenChange={setSheetOpen}
        onClaim={(id) => setUnassignedStories(prev => prev.filter(s => s.id !== id))}
      />
    </div>
  )
}
