'use client'

import { useState, useEffect, useRef, useCallback, memo } from 'react';
import { Note } from '@/lib/types';
import { NoteCard } from './note-card';
import { NoteEditor } from './note-editor';
import { updateFullOrder } from '@/app/actions/notes';
import { useResizeObserver } from '@/hooks/use-resize-observer';

interface MasonryGridProps {
  notes: Note[];
}

interface MasonryItemProps {
  note: Note;
  onEdit: (note: Note, readOnly?: boolean) => void;
  onResize: () => void;
}

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 }: 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} />
      </div>
    </div>
  );
}, (prev, next) => {
  // Custom comparison to avoid re-render on function prop changes if note data is same
  return prev.note === next.note;
});

export function MasonryGrid({ notes }: MasonryGridProps) {
  const [editingNote, setEditingNote] = useState<{ note: Note; readOnly?: boolean } | null>(null);
  const pinnedGridRef = useRef<HTMLDivElement>(null);
  const othersGridRef = useRef<HTMLDivElement>(null);
  const pinnedMuuri = useRef<any>(null);
  const othersMuuri = useRef<any>(null);
  const isDraggingRef = useRef(false);

  const pinnedNotes = notes.filter(n => n.isPinned).sort((a, b) => a.order - b.order);
  const othersNotes = notes.filter(n => !n.isPinned).sort((a, b) => a.order - b.order);

  const handleDragEnd = async (grid: any) => {
    if (!grid) return;
    
    // Prevent layout refresh during server update
    isDraggingRef.current = true;
    
    const items = grid.getItems();
    const ids = items
      .map((item: any) => item.getElement()?.getAttribute('data-id'))
      .filter((id: any): id is string => !!id);
    
    try {
      await updateFullOrder(ids);
    } catch (error) {
      console.error('Failed to persist order:', error);
    } finally {
      // Reset after animation/server roundtrip
      setTimeout(() => {
        isDraggingRef.current = false;
      }, 1000);
    }
  };

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

  useEffect(() => {
    let isMounted = true;

    const initMuuri = async () => {
      // 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,
        // On mobile, restrict drag to handle to allow scrolling. On desktop, allow drag from anywhere.
        dragHandle: isMobile ? '.drag-handle' : undefined, 
        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;
          },
        },
      };

      if (pinnedGridRef.current && !pinnedMuuri.current && pinnedNotes.length > 0) {
        pinnedMuuri.current = new MuuriClass(pinnedGridRef.current, layoutOptions)
          .on('dragEnd', () => handleDragEnd(pinnedMuuri.current));
      }

      if (othersGridRef.current && !othersMuuri.current && othersNotes.length > 0) {
        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;
    };
  }, [pinnedNotes.length > 0, othersNotes.length > 0]);

  // Synchronize items when notes change (e.g. searching, adding)
  useEffect(() => {
    if (isDraggingRef.current) return;

    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">Pinned</h2>
          <div ref={pinnedGridRef} className="relative min-h-[100px]">
            {pinnedNotes.map(note => (
              <MasonryItem
                key={note.id}
                note={note}
                onEdit={(note, readOnly) => setEditingNote({ note, readOnly })}
                onResize={refreshLayout}
              />
            ))}
          </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">Others</h2>
          )}
          <div ref={othersGridRef} className="relative min-h-[100px]">
            {othersNotes.map(note => (
              <MasonryItem
                key={note.id}
                note={note}
                onEdit={(note, readOnly) => setEditingNote({ note, readOnly })}
                onResize={refreshLayout}
              />
            ))}
          </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>
  );
}
