import { Plus } from 'lucide-react';
import { useMemo, useState } from 'react';
import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';

export type KanbanColumn = {
    value: string;
    label: string;
};

export type KanbanCard = {
    id: number;
    code: string;
    title: string;
    status: string;
    priority_label: string;
    project?: { code: string; name: string } | null;
    assignee?: { name: string } | null;
    due_date?: string | null;
    ticket?: { code: string } | null;
    completion_percent?: number;
    category?: string;
    category_label?: string;
};

type Props = {
    columns: KanbanColumn[];
    items: KanbanCard[];
    canDrag: boolean;
    canCreate?: boolean;
    onMove: (itemId: number, status: string) => void;
    onCardClick?: (item: KanbanCard) => void;
    onAddColumn?: (column: KanbanColumn) => void;
};

const PRIORITY_CLASSES: Record<string, string> = {
    Basse: 'border-l-slate-300',
    Moyenne: 'border-l-blue-400',
    Haute: 'border-l-amber-500',
    Urgente: 'border-l-red-500',
};

function formatDueDate(value: string): string {
    return new Intl.DateTimeFormat('fr-FR', {
        day: '2-digit',
        month: 'short',
        year: 'numeric',
    }).format(new Date(`${value}T12:00:00`));
}

function dueDateTone(
    dueDate: string | null | undefined,
): 'overdue' | 'soon' | 'ok' | null {
    if (!dueDate) {
        return null;
    }

    const today = new Date();
    today.setHours(0, 0, 0, 0);
    const due = new Date(`${dueDate}T12:00:00`);
    due.setHours(0, 0, 0, 0);

    const diffDays = Math.round(
        (due.getTime() - today.getTime()) / (1000 * 60 * 60 * 24),
    );

    if (diffDays < 0) {
        return 'overdue';
    }

    if (diffDays <= 3) {
        return 'soon';
    }

    return 'ok';
}

export function KanbanBoard({
    columns,
    items,
    canDrag,
    canCreate = false,
    onMove,
    onCardClick,
    onAddColumn,
}: Props) {
    const [draggingId, setDraggingId] = useState<number | null>(null);
    const [overColumn, setOverColumn] = useState<string | null>(null);

    const itemsByColumn = useMemo(() => {
        const grouped = Object.fromEntries(
            columns.map((column) => [column.value, [] as KanbanCard[]]),
        ) as Record<string, KanbanCard[]>;

        for (const item of items) {
            if (grouped[item.status]) {
                grouped[item.status].push(item);
            }
        }

        return grouped;
    }, [columns, items]);

    function handleDrop(columnValue: string) {
        if (draggingId === null || !canDrag) {
            return;
        }

        const item = items.find((entry) => entry.id === draggingId);

        if (item && item.status !== columnValue) {
            onMove(draggingId, columnValue);
        }

        setDraggingId(null);
        setOverColumn(null);
    }

    return (
        <div className="flex gap-4 overflow-x-auto pb-2">
            {columns.map((column) => {
                const columnItems = itemsByColumn[column.value] ?? [];
                const isOver = overColumn === column.value;

                return (
                    <div
                        key={column.value}
                        className="flex w-72 shrink-0 flex-col"
                        onDragOver={(event) => {
                            if (!canDrag) {
                                return;
                            }

                            event.preventDefault();
                            setOverColumn(column.value);
                        }}
                        onDragLeave={() => {
                            setOverColumn((current) =>
                                current === column.value ? null : current,
                            );
                        }}
                        onDrop={(event) => {
                            event.preventDefault();
                            handleDrop(column.value);
                        }}
                    >
                        <div className="mb-3 flex items-center justify-between gap-2">
                            <h3 className="text-sm font-medium">
                                {column.label}
                            </h3>
                            <div className="flex items-center gap-1">
                                <span className="text-muted-foreground text-xs tabular-nums">
                                    {columnItems.length}
                                </span>
                                {canCreate && onAddColumn && (
                                    <Button
                                        type="button"
                                        variant="ghost"
                                        size="icon"
                                        className="size-7"
                                        onClick={() => onAddColumn(column)}
                                        aria-label={`Ajouter dans ${column.label}`}
                                    >
                                        <Plus className="size-4" />
                                    </Button>
                                )}
                            </div>
                        </div>

                        <div
                            className={cn(
                                'flex min-h-40 flex-1 flex-col gap-2 rounded-lg border border-dashed p-2 transition-colors',
                                isOver &&
                                    canDrag &&
                                    'border-primary bg-primary/5',
                            )}
                        >
                            {columnItems.length === 0 ? (
                                <p className="text-muted-foreground px-2 py-6 text-center text-xs">
                                    Aucun élément
                                </p>
                            ) : (
                                columnItems.map((item) => {
                                    const tone = dueDateTone(item.due_date);

                                    return (
                                        <article
                                            key={item.id}
                                            draggable={canDrag}
                                            onDragStart={() =>
                                                setDraggingId(item.id)
                                            }
                                            onDragEnd={() => {
                                                setDraggingId(null);
                                                setOverColumn(null);
                                            }}
                                            onClick={() => onCardClick?.(item)}
                                            className={cn(
                                                'bg-card rounded-md border border-l-4 p-3 shadow-xs',
                                                canDrag
                                                    ? 'cursor-grab active:cursor-grabbing'
                                                    : 'cursor-pointer',
                                                onCardClick &&
                                                    'hover:bg-muted/40',
                                                PRIORITY_CLASSES[
                                                    item.priority_label
                                                ] ?? 'border-l-slate-300',
                                                draggingId === item.id &&
                                                    'opacity-50',
                                            )}
                                        >
                                            <div className="mb-1 flex items-start justify-between gap-2">
                                                <p className="line-clamp-2 text-sm font-medium">
                                                    {item.title}
                                                </p>
                                                <span className="text-muted-foreground shrink-0 font-mono text-xs">
                                                    {item.code}
                                                </span>
                                            </div>

                                            {item.project && (
                                                <p className="text-muted-foreground mb-2 line-clamp-1 text-xs">
                                                    {item.project.code} —{' '}
                                                    {item.project.name}
                                                </p>
                                            )}

                                            {item.category_label && (
                                                <p className="text-muted-foreground mb-2 text-xs">
                                                    {item.category_label}
                                                </p>
                                            )}

                                            {item.completion_percent !==
                                                undefined && (
                                                <div className="mb-2 flex items-center gap-2">
                                                    <div className="bg-muted h-1.5 flex-1 overflow-hidden rounded-full">
                                                        <div
                                                            className="bg-primary h-full"
                                                            style={{
                                                                width: `${item.completion_percent}%`,
                                                            }}
                                                        />
                                                    </div>
                                                    <span className="text-muted-foreground shrink-0 text-xs tabular-nums">
                                                        {
                                                            item.completion_percent
                                                        }{' '}
                                                        %
                                                    </span>
                                                </div>
                                            )}

                                            <div className="flex flex-wrap items-center gap-x-2 gap-y-1 text-xs">
                                                {item.assignee && (
                                                    <span className="text-muted-foreground">
                                                        {item.assignee.name}
                                                    </span>
                                                )}
                                                {item.due_date && (
                                                    <span
                                                        className={cn(
                                                            'rounded px-1.5 py-0.5 font-medium',
                                                            tone ===
                                                                'overdue' &&
                                                                'bg-red-50 text-red-700 dark:bg-red-950/40 dark:text-red-400',
                                                            tone === 'soon' &&
                                                                'bg-amber-50 text-amber-700 dark:bg-amber-950/40 dark:text-amber-400',
                                                            tone === 'ok' &&
                                                                'text-muted-foreground',
                                                        )}
                                                    >
                                                        {formatDueDate(
                                                            item.due_date,
                                                        )}
                                                    </span>
                                                )}
                                                {item.ticket && (
                                                    <span className="text-muted-foreground font-mono">
                                                        {item.ticket.code}
                                                    </span>
                                                )}
                                            </div>
                                        </article>
                                    );
                                })
                            )}
                        </div>
                    </div>
                );
            })}
        </div>
    );
}
