'use client';
import { jsx as _jsx } from "react/jsx-runtime";
import { useState, useMemo, useCallback } from 'react';
import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors, } from '@dnd-kit/core';
import { sortableKeyboardCoordinates } from '@dnd-kit/sortable';
import { cn } from '../../../lib/utils.js';
import { TaskState } from '../../../../../../packages/core/src/domain/generated/output.js';
import { SdlcColumn } from './sdlc-column.js';
/**
 * Fixed column order for the SDLC board — left to right.
 */
const COLUMN_ORDER = [TaskState.Todo, TaskState.WIP, TaskState.Review, TaskState.Done];
/**
 * Human-readable column titles — WIP becomes "In Progress" for readability.
 */
const COLUMN_TITLES = {
    [TaskState.Todo]: 'Todo',
    [TaskState.WIP]: 'In Progress',
    [TaskState.Review]: 'Review',
    [TaskState.Done]: 'Done',
};
export function SdlcBoard({ epics, onTaskStatusChange, onCardClick, className }) {
    // Flatten epics into a map of taskId → FlatTaskEntry for drag resolution,
    // and keep a local status override map for optimistic updates.
    const baseEntries = useMemo(() => {
        const entries = [];
        for (const { feature, tasks } of epics) {
            for (const { task, subTasks } of tasks) {
                entries.push({
                    task,
                    subTasks,
                    epicName: feature.name,
                    status: task.status,
                });
            }
        }
        return entries;
    }, [epics]);
    // Optimistic overrides: taskId → TaskState.  Only populated on drag.
    const [statusOverrides, setStatusOverrides] = useState(new Map());
    // Merge overrides into entries so columns always reflect the optimistic state.
    const entries = useMemo(() => {
        if (statusOverrides.size === 0)
            return baseEntries;
        return baseEntries.map((e) => {
            const override = statusOverrides.get(e.task.id);
            return override !== undefined ? { ...e, status: override } : e;
        });
    }, [baseEntries, statusOverrides]);
    // Distribute into columns, sorted by sortOrder within each column.
    const columns = useMemo(() => {
        const map = {
            [TaskState.Todo]: [],
            [TaskState.WIP]: [],
            [TaskState.Review]: [],
            [TaskState.Done]: [],
        };
        for (const entry of entries) {
            const bucket = map[entry.status];
            if (bucket) {
                bucket.push(entry);
            }
        }
        // Sort within each column by sortOrder ASC
        for (const bucket of Object.values(map)) {
            bucket.sort((a, b) => a.task.sortOrder - b.task.sortOrder);
        }
        return map;
    }, [entries]);
    const sensors = useSensors(useSensor(PointerSensor, {
        activationConstraint: { distance: 8 },
    }), useSensor(KeyboardSensor, {
        coordinateGetter: sortableKeyboardCoordinates,
    }));
    const handleDragEnd = useCallback((event) => {
        const { active, over } = event;
        if (!over || active.id === over.id)
            return;
        const activeId = String(active.id);
        const overId = String(over.id);
        // Determine target status: dropped on a column directly (overId is a TaskState)
        // or dropped on a card (resolve that card's current status).
        let targetStatus;
        const isColumnDrop = COLUMN_ORDER.includes(overId);
        if (isColumnDrop) {
            targetStatus = overId;
        }
        else {
            // Dropped on a card — find its current (possibly optimistic) status.
            const targetEntry = entries.find((e) => e.task.id === overId);
            targetStatus = targetEntry?.status;
        }
        if (!targetStatus)
            return;
        const draggedEntry = entries.find((e) => e.task.id === activeId);
        if (!draggedEntry)
            return;
        // No-op if the card is already in the target column.
        if (draggedEntry.status === targetStatus)
            return;
        // Optimistic local update.
        setStatusOverrides((prev) => {
            const next = new Map(prev);
            next.set(activeId, targetStatus);
            return next;
        });
        // Notify parent; parent will eventually re-render with updated epics
        // causing the override to become redundant (and it will be a no-op).
        onTaskStatusChange?.(activeId, targetStatus);
    }, [entries, onTaskStatusChange]);
    return (_jsx("div", { "data-testid": "sdlc-board", className: cn('flex gap-4 overflow-x-auto pb-4', className), children: _jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: COLUMN_ORDER.map((status) => (_jsx(SdlcColumn, { status: status, title: COLUMN_TITLES[status], tasks: columns[status], onCardClick: onCardClick }, status))) }) }));
}
