'use client'

import { useState, useEffect, useRef, useCallback, memo, useMemo } from 'react';
import { Note } from '@/lib/types';
import { NoteCard } from './note-card';
import { NoteEditor } from './note-editor';
import { updateFullOrderWithoutRevalidation } from '@/app/actions/notes';
import { useResizeObserver } from '@/hooks/use-resize-observer';
import { useNotebookDrag } from '@/context/notebook-drag-context';
import { useLanguage } from '@/lib/i18n';

interface MasonryGridProps {
  notes: Note[];
  onEdit?: (note: Note, readOnly?: boolean) => void;
}

interface MasonryItemProps {
  note: Note;
  onEdit: (note: Note, readOnly?: boolean) => void;
  onResize: () => void;
  onDragStart?: (noteId: string) => void;
  onDragEnd?: () => void;
  isDragging?: boolean;
}

function getSizeClasses(size: string = 'small') {
  switch (size) {
    case 'medium':
      return 'w-full sm:w-full lg:w-2/3 xl:w-2/4 2xl:w-2/5';
    case 'large':
      return 'w-full';
    case 'small':
    default:
      return 'w-full sm:w-1/2 lg:w-1/3 xl:w-1/4 2xl:w-1/5';
  }
}

const MasonryItem = memo(function MasonryItem({ note, onEdit, onResize, onDragStart, onDragEnd, isDragging }: MasonryItemProps) {
  const resizeRef = useResizeObserver(onResize);

  const sizeClasses = getSizeClasses(note.size);

  return (
    <div
      className={`masonry-item absolute p-2 ${sizeClasses}`}
      data-id={note.id}
      ref={resizeRef as any}
    >
      <div className="masonry-item-content relative">
        <NoteCard
          note={note}
          onEdit={onEdit}
          onDragStart={onDragStart}
          onDragEnd={onDragEnd}
          isDragging={isDragging}
        />
      </div>
    </div>
  );
}, (prev, next) => {
  // Custom comparison to avoid re-render on function prop changes if note data is same
  return prev.note.id === next.note.id && prev.note.order === next.note.order && prev.isDragging === next.isDragging;
});

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

  // Use external onEdit if provided, otherwise use internal state
  const handleEdit = useCallback((note: Note, readOnly?: boolean) => {
    if (onEdit) {
      onEdit(note, readOnly);
    } else {
      setEditingNote({ note, readOnly });
    }
  }, [onEdit]);

  const pinnedGridRef = useRef<HTMLDivElement>(null);
  const othersGridRef = useRef<HTMLDivElement>(null);
  const pinnedMuuri = useRef<any>(null);
  const othersMuuri = useRef<any>(null);

  // Memoize filtered and sorted notes to avoid recalculation on every render
  const pinnedNotes = useMemo(
    () => notes.filter(n => n.isPinned).sort((a, b) => a.order - b.order),
    [notes]
  );
  const othersNotes = useMemo(
    () => notes.filter(n => !n.isPinned).sort((a, b) => a.order - b.order),
    [notes]
  );

  // CRITICAL: Sync editingNote when underlying note changes (e.g., after moving to notebook)
  // This ensures the NoteEditor gets the updated note with the new notebookId
  useEffect(() => {
    if (!editingNote) return;

    // Find the updated version of the currently edited note in the notes array
    const updatedNote = notes.find(n => n.id === editingNote.note.id);

    if (updatedNote) {
      // Check if any key properties changed (especially notebookId)
      const notebookIdChanged = updatedNote.notebookId !== editingNote.note.notebookId;

      if (notebookIdChanged) {
                // Update the editingNote with the new data
        setEditingNote(prev => prev ? { ...prev, note: updatedNote } : null);
      }
    }
  }, [notes, editingNote]);

  const handleDragEnd = useCallback(async (grid: any) => {
    if (!grid) return;

    const items = grid.getItems();
    const ids = items
      .map((item: any) => item.getElement()?.getAttribute('data-id'))
      .filter((id: any): id is string => !!id);

    try {
      // Save order to database WITHOUT revalidating the page
      // Muuri has already updated the visual layout, so we don't need to reload
      await updateFullOrderWithoutRevalidation(ids);
    } catch (error) {
      console.error('Failed to persist order:', error);
    }
  }, []);

  const refreshLayout = useCallback(() => {
    // Use requestAnimationFrame for smoother updates
    requestAnimationFrame(() => {
      if (pinnedMuuri.current) {
        pinnedMuuri.current.refreshItems().layout();
      }
      if (othersMuuri.current) {
        othersMuuri.current.refreshItems().layout();
      }
    });
  }, []);

  // Initialize Muuri grids once on mount and sync when needed
  useEffect(() => {
    let isMounted = true;
    let muuriInitialized = false;

    const initMuuri = async () => {
      // Prevent duplicate initialization
      if (muuriInitialized) return;
      muuriInitialized = true;

      // Import web-animations-js polyfill
      await import('web-animations-js');
      // Dynamic import of Muuri to avoid SSR window error
      const MuuriClass = (await import('muuri')).default;

      if (!isMounted) return;

      // Detect if we are on a touch device (mobile behavior)
      const isMobile = window.matchMedia('(pointer: coarse)').matches;

      const layoutOptions = {
        dragEnabled: true,
        // Always use specific drag handle to avoid conflicts
        dragHandle: '.muuri-drag-handle',
        dragContainer: document.body,
        dragStartPredicate: {
          distance: 10,
          delay: 0,
        },
        dragPlaceholder: {
          enabled: true,
          createElement: (item: any) => {
            const el = item.getElement().cloneNode(true);
            el.style.opacity = '0.5';
            return el;
          },
        },
        dragAutoScroll: {
          targets: [window],
          speed: (item: any, target: any, intersection: any) => {
            return intersection * 20;
          },
        },
      };

      // Initialize pinned grid
      if (pinnedGridRef.current && !pinnedMuuri.current) {
        pinnedMuuri.current = new MuuriClass(pinnedGridRef.current, layoutOptions)
          .on('dragEnd', () => handleDragEnd(pinnedMuuri.current));
      }

      // Initialize others grid
      if (othersGridRef.current && !othersMuuri.current) {
        othersMuuri.current = new MuuriClass(othersGridRef.current, layoutOptions)
          .on('dragEnd', () => handleDragEnd(othersMuuri.current));
      }
    };

    initMuuri();

    return () => {
      isMounted = false;
      pinnedMuuri.current?.destroy();
      othersMuuri.current?.destroy();
      pinnedMuuri.current = null;
      othersMuuri.current = null;
    };
    // Only run once on mount
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Synchronize items when notes change (e.g. searching, adding)
  useEffect(() => {
    requestAnimationFrame(() => {
      if (pinnedMuuri.current) {
        pinnedMuuri.current.refreshItems().layout();
      }
      if (othersMuuri.current) {
        othersMuuri.current.refreshItems().layout();
      }
    });
  }, [notes]);

  return (
    <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>
          <div ref={pinnedGridRef} className="relative min-h-[100px]">
            {pinnedNotes.map(note => (
              <MasonryItem
                key={note.id}
                note={note}
                onEdit={handleEdit}
                onResize={refreshLayout}
                onDragStart={startDrag}
                onDragEnd={endDrag}
                isDragging={draggedNoteId === note.id}
              />
            ))}
          </div>
        </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>
          )}
          <div ref={othersGridRef} className="relative min-h-[100px]">
            {othersNotes.map(note => (
              <MasonryItem
                key={note.id}
                note={note}
                onEdit={handleEdit}
                onResize={refreshLayout}
                onDragStart={startDrag}
                onDragEnd={endDrag}
                isDragging={draggedNoteId === note.id}
              />
            ))}
          </div>
        </div>
      )}

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

      <style jsx global>{`
        .masonry-item {
          display: block;
          position: absolute;
          z-index: 1;
        }
        .masonry-item.muuri-item-dragging {
          z-index: 3;
        }
        .masonry-item.muuri-item-releasing {
          z-index: 2;
        }
        .masonry-item.muuri-item-hidden {
          z-index: 0;
        }
        .masonry-item-content {
          position: relative;
          width: 100%;
          height: 100%;
        }
      `}</style>
    </div>
  );
}
