'use client'

import { useState, useEffect, useCallback, memo, useMemo, useRef } from 'react';
import {
  DndContext,
  DragEndEvent,
  DragOverlay,
  DragStartEvent,
  PointerSensor,
  TouchSensor,
  closestCenter,
  useSensor,
  useSensors,
} from '@dnd-kit/core';
import {
  SortableContext,
  arrayMove,
  rectSortingStrategy,
  useSortable,
} from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { Note } from '@/lib/types';
import { NoteCard } from './note-card';
import { updateFullOrderWithoutRevalidation } from '@/app/actions/notes';
import { useNotebookDrag } from '@/context/notebook-drag-context';
import { useLanguage } from '@/lib/i18n';
import dynamic from 'next/dynamic';
import './masonry-grid.css';

// Lazy-load NoteEditor — uniquement chargé au clic
const NoteEditor = dynamic(
  () => import('./note-editor').then(m => ({ default: m.NoteEditor })),
  { ssr: false }
);

interface MasonryGridProps {
  notes: Note[];
  onEdit?: (note: Note, readOnly?: boolean) => void;
  onSizeChange?: (noteId: string, size: 'small' | 'medium' | 'large') => void;
}

// ─────────────────────────────────────────────
// Sortable Note Item
// ─────────────────────────────────────────────
interface SortableNoteProps {
  note: Note;
  onEdit: (note: Note, readOnly?: boolean) => void;
  onSizeChange: (noteId: string, newSize: 'small' | 'medium' | 'large') => void;
  onDragStartNote?: (noteId: string) => void;
  onDragEndNote?: () => void;
  isDragging?: boolean;
  isOverlay?: boolean;
}

const SortableNoteItem = memo(function SortableNoteItem({
  note,
  onEdit,
  onSizeChange,
  onDragStartNote,
  onDragEndNote,
  isDragging,
  isOverlay,
}: SortableNoteProps) {
  const {
    attributes,
    listeners,
    setNodeRef,
    transform,
    transition,
    isDragging: isSortableDragging,
  } = useSortable({ id: note.id });

  const style: React.CSSProperties = {
    transform: CSS.Transform.toString(transform),
    transition,
    opacity: isSortableDragging && !isOverlay ? 0.3 : 1,
  };

  return (
    <div
      ref={setNodeRef}
      style={style}
      {...attributes}
      {...listeners}
      className="masonry-sortable-item"
      data-id={note.id}
      data-size={note.size}
    >
      <NoteCard
        note={note}
        onEdit={onEdit}
        onDragStart={onDragStartNote}
        onDragEnd={onDragEndNote}
        isDragging={isDragging}
        onSizeChange={(newSize) => onSizeChange(note.id, newSize)}
      />
    </div>
  );
})

// ─────────────────────────────────────────────
// Sortable Grid Section (pinned or others)
// ─────────────────────────────────────────────
interface SortableGridSectionProps {
  notes: Note[];
  onEdit: (note: Note, readOnly?: boolean) => void;
  onSizeChange: (noteId: string, newSize: 'small' | 'medium' | 'large') => void;
  draggedNoteId: string | null;
  onDragStartNote: (noteId: string) => void;
  onDragEndNote: () => void;
}

const SortableGridSection = memo(function SortableGridSection({
  notes,
  onEdit,
  onSizeChange,
  draggedNoteId,
  onDragStartNote,
  onDragEndNote,
}: SortableGridSectionProps) {
  const ids = useMemo(() => notes.map(n => n.id), [notes]);

  return (
    <SortableContext items={ids} strategy={rectSortingStrategy}>
      <div className="masonry-css-grid">
        {notes.map(note => (
          <SortableNoteItem
            key={note.id}
            note={note}
            onEdit={onEdit}
            onSizeChange={onSizeChange}
            onDragStartNote={onDragStartNote}
            onDragEndNote={onDragEndNote}
            isDragging={draggedNoteId === note.id}
          />
        ))}
      </div>
    </SortableContext>
  );
});

// ─────────────────────────────────────────────
// Main MasonryGrid component
// ─────────────────────────────────────────────
export function MasonryGrid({ notes, onEdit, onSizeChange }: MasonryGridProps) {
  const { t } = useLanguage();
  const [editingNote, setEditingNote] = useState<{ note: Note; readOnly?: boolean } | null>(null);
  const { startDrag, endDrag, draggedNoteId } = useNotebookDrag();

  // Local notes state for optimistic size/order updates
  const [localNotes, setLocalNotes] = useState<Note[]>(notes);

  useEffect(() => {
    setLocalNotes(prev => {
      const localSizeMap = new Map(prev.map(n => [n.id, n.size]))
      return notes.map(n => ({ ...n, size: localSizeMap.get(n.id) ?? n.size }))
    })
  }, [notes]);

  const pinnedNotes = useMemo(() => localNotes.filter(n => n.isPinned), [localNotes]);
  const othersNotes = useMemo(() => localNotes.filter(n => !n.isPinned), [localNotes]);

  const [activeId, setActiveId] = useState<string | null>(null);
  const activeNote = useMemo(
    () => localNotes.find(n => n.id === activeId) ?? null,
    [localNotes, activeId]
  );

  const handleEdit = useCallback((note: Note, readOnly?: boolean) => {
    if (onEdit) {
      onEdit(note, readOnly);
    } else {
      setEditingNote({ note, readOnly });
    }
  }, [onEdit]);

  const handleSizeChange = useCallback((noteId: string, newSize: 'small' | 'medium' | 'large') => {
    setLocalNotes(prev => prev.map(n => n.id === noteId ? { ...n, size: newSize } : n));
    onSizeChange?.(noteId, newSize);
  }, [onSizeChange]);

  // @dnd-kit sensors — pointer (desktop) + touch (mobile)
  const sensors = useSensors(
    useSensor(PointerSensor, {
      activationConstraint: { distance: 8 }, // Évite les activations accidentelles
    }),
    useSensor(TouchSensor, {
      activationConstraint: { delay: 200, tolerance: 8 }, // Long-press sur mobile
    })
  );

  const localNotesRef = useRef<Note[]>(localNotes)
  useEffect(() => {
    localNotesRef.current = localNotes
  }, [localNotes])

  const handleDragStart = useCallback((event: DragStartEvent) => {
    setActiveId(event.active.id as string);
    startDrag(event.active.id as string);
  }, [startDrag]);

  const handleDragEnd = useCallback(async (event: DragEndEvent) => {
    const { active, over } = event;
    setActiveId(null);
    endDrag();

    if (!over || active.id === over.id) return;

    const reordered = arrayMove(
      localNotesRef.current,
      localNotesRef.current.findIndex(n => n.id === active.id),
      localNotesRef.current.findIndex(n => n.id === over.id),
    );

    if (reordered.length === 0) return;

    setLocalNotes(reordered);
    // Persist order outside of setState to avoid "setState in render" warning
    const ids = reordered.map(n => n.id);
    updateFullOrderWithoutRevalidation(ids).catch(err => {
      console.error('Failed to persist order:', err);
    });
  }, [endDrag]);

  return (
    <DndContext
      id="masonry-dnd"
      sensors={sensors}
      collisionDetection={closestCenter}
      onDragStart={handleDragStart}
      onDragEnd={handleDragEnd}
    >
      <div className="masonry-container">
        {pinnedNotes.length > 0 && (
          <div className="mb-8">
            <h2 className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-3 px-2">
              {t('notes.pinned')}
            </h2>
            <SortableGridSection
              notes={pinnedNotes}
              onEdit={handleEdit}
              onSizeChange={handleSizeChange}
              draggedNoteId={draggedNoteId}
              onDragStartNote={startDrag}
              onDragEndNote={endDrag}
            />
          </div>
        )}

        {othersNotes.length > 0 && (
          <div>
            {pinnedNotes.length > 0 && (
              <h2 className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-3 px-2">
                {t('notes.others')}
              </h2>
            )}
            <SortableGridSection
              notes={othersNotes}
              onEdit={handleEdit}
              onSizeChange={handleSizeChange}
              draggedNoteId={draggedNoteId}
              onDragStartNote={startDrag}
              onDragEndNote={endDrag}
            />
          </div>
        )}
      </div>

      {/* DragOverlay — montre une copie flottante pendant le drag */}
      <DragOverlay>
        {activeNote ? (
          <div className="masonry-sortable-item masonry-drag-overlay" data-size={activeNote.size}>
            <NoteCard
              note={activeNote}
              onEdit={handleEdit}
              isDragging={true}
              onSizeChange={(newSize) => handleSizeChange(activeNote.id, newSize)}
            />
          </div>
        ) : null}
      </DragOverlay>

      {editingNote && (
        <NoteEditor
          note={editingNote.note}
          readOnly={editingNote.readOnly}
          onClose={() => setEditingNote(null)}
        />
      )}
    </DndContext>
  );
}
