'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';
import { DEFAULT_LAYOUT, calculateColumns, calculateItemWidth, isMobileViewport } from '@/config/masonry-layout';
import './masonry-grid.css'; // Force rebuild: Spacing update verification

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

interface MasonryItemProps {
  note: Note;
  onEdit: (note: Note, readOnly?: boolean) => void;
  onResize: () => void;
  onNoteSizeChange: (noteId: string, newSize: 'small' | 'medium' | 'large') => void;
  onDragStart?: (noteId: string) => void;
  onDragEnd?: () => void;
  isDragging?: boolean;
}

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

  useEffect(() => {
    onResize();
    const timer = setTimeout(onResize, 300);
    return () => clearTimeout(timer);
  }, [note.size, onResize]);

  return (
    <div
      className="masonry-item absolute py-1"
      data-id={note.id}
      data-size={note.size}
      data-draggable="true"
    >
      <div className="masonry-item-content relative" ref={resizeRef as any}>
        <NoteCard
          note={note}
          onEdit={onEdit}
          onDragStart={onDragStart}
          onDragEnd={onDragEnd}
          isDragging={isDragging}
          onResize={onResize}
          onSizeChange={(newSize) => onNoteSizeChange(note.id, newSize)}
        />
      </div>
    </div>
  );
})

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

  // Local state for notes with dynamic size updates
  // This allows size changes to propagate immediately without waiting for server
  const [localNotes, setLocalNotes] = useState<Note[]>(notes);

  // Sync localNotes when parent notes prop changes
  useEffect(() => {
    setLocalNotes(notes);
  }, [notes]);

  // Callback for when a note's size changes - update local state immediately
  const handleNoteSizeChange = useCallback((noteId: string, newSize: 'small' | 'medium' | 'large') => {
    setLocalNotes(prevNotes =>
      prevNotes.map(n => n.id === noteId ? { ...n, size: newSize } : n)
    );
  }, []);

  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 notes from localNotes (which includes dynamic size updates)
  const pinnedNotes = useMemo(
    () => localNotes.filter(n => n.isPinned),
    [localNotes]
  );
  const othersNotes = useMemo(
    () => localNotes.filter(n => !n.isPinned),
    [localNotes]
  );

  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 triggering a full page refresh
      // Muuri has already updated the visual layout
      await updateFullOrderWithoutRevalidation(ids);
    } catch (error) {
      console.error('Failed to persist order:', error);
    }
  }, []);

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

  const applyItemDimensions = useCallback((grid: any, containerWidth: number) => {
    if (!grid) return;

    // Calculate columns and item width based on container width
    const columns = calculateColumns(containerWidth);
    const baseItemWidth = calculateItemWidth(containerWidth, columns);

    const items = grid.getItems();
    items.forEach((item: any) => {
      const el = item.getElement();
      if (el) {
        const size = el.getAttribute('data-size') || 'small';
        let width = baseItemWidth;
        if (columns >= 2 && size === 'medium') {
          width = Math.min(baseItemWidth * 1.5, containerWidth);
        } else if (columns >= 2 && size === 'large') {
          width = Math.min(baseItemWidth * 2, containerWidth);
        }
        el.style.width = `${width}px`;
      }
    });
  }, []);

  // 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 isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
      const isMobileWidth = window.innerWidth < 768;
      const isMobile = isTouchDevice || isMobileWidth;

      // Get container width for responsive calculation
      const containerWidth = window.innerWidth - 32; // Subtract padding
      const columns = calculateColumns(containerWidth);
      const itemWidth = calculateItemWidth(containerWidth, columns);



      const layoutOptions = {
        dragEnabled: !isMobile,
        // Use drag handle for mobile devices to allow smooth scrolling
        // On desktop, whole card is draggable (no handle needed)
        dragHandle: isMobile ? '.muuri-drag-handle' : undefined,
        dragContainer: document.body,
        dragStartPredicate: {
          distance: 10,
          delay: 0,
        },
        dragPlaceholder: {
          enabled: true,
          createElement: (item: any) => {
            const el = item.getElement().cloneNode(true);
            // Styles are now handled purely by CSS (.muuri-item-placeholder)
            // to avoid inline style conflicts and "grayed out/tilted" look
            return el;
          },
        },
        dragAutoScroll: {
          targets: [window],
          speed: (item: any, target: any, intersection: any) => {
            return intersection * 30; // Faster auto-scroll for better UX
          },
          threshold: 50, // Start auto-scroll earlier (50px from edge)
          smoothStop: true, // Smooth deceleration
        },
        // LAYOUT OPTIONS - Configure masonry grid behavior
        // These options are critical for proper masonry layout with different item sizes
        layoutDuration: 300,
        layoutEasing: 'cubic-bezier(0.25, 1, 0.5, 1)',
        fillGaps: true,
        horizontal: false,
        alignRight: false,
        alignBottom: false,
        rounding: false,
        // CRITICAL: Enable true masonry layout for different item sizes
        layout: {
          fillGaps: true,
          horizontal: false,
          alignRight: false,
          alignBottom: false,
          rounding: false,
        },
      };

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

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

      // Signal that Muuri is ready so sync/resize effects can run
      setMuuriReady(true);
    };

    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
  }, []);

  // Container ref for ResizeObserver
  const containerRef = useRef<HTMLDivElement>(null);

  // Synchronize items when notes change (e.g. searching, adding)
  useEffect(() => {
    if (!muuriReady) return;
    const syncGridItems = (grid: any, gridRef: React.RefObject<HTMLDivElement | null>, notesArray: Note[]) => {
      if (!grid || !gridRef.current) return;

      const containerWidth = containerRef.current?.getBoundingClientRect().width || window.innerWidth - 32;
      const columns = calculateColumns(containerWidth);
      const itemWidth = calculateItemWidth(containerWidth, columns);

      // Get current DOM elements and Muuri items
      const domElements = Array.from(gridRef.current.children) as HTMLElement[];
      const muuriItems = grid.getItems();

      // Map Muuri items to their elements for comparison
      const muuriElements = muuriItems.map((item: any) => item.getElement());

      // Find new elements to add (in DOM but not in Muuri)
      const newElements = domElements.filter(el => !muuriElements.includes(el));

      // Find elements to remove (in Muuri but not in DOM)
      const removedItems = muuriItems.filter((item: any) =>
        !domElements.includes(item.getElement())
      );

      // Remove old items
      if (removedItems.length > 0) {
        grid.remove(removedItems, { layout: false });
      }

      // Add new items with correct width based on size
      if (newElements.length > 0) {
        newElements.forEach(el => {
          const size = el.getAttribute('data-size') || 'small';
          let width = itemWidth;
          if (columns >= 2 && size === 'medium') {
            width = Math.min(itemWidth * 1.5, containerWidth);
          } else if (columns >= 2 && size === 'large') {
            width = Math.min(itemWidth * 2, containerWidth);
          }
          el.style.width = `${width}px`;
        });
        grid.add(newElements, { layout: false });
      }

      // Update all item widths to ensure consistency (size-aware)
      domElements.forEach(el => {
        const size = el.getAttribute('data-size') || 'small';
        let width = itemWidth;
        if (columns >= 2 && size === 'medium') {
          width = Math.min(itemWidth * 1.5, containerWidth);
        } else if (columns >= 2 && size === 'large') {
          width = Math.min(itemWidth * 2, containerWidth);
        }
        el.style.width = `${width}px`;
      });

      // Refresh and layout
      grid.refreshItems().layout();
    };

    // Use requestAnimationFrame to ensure DOM is updated before syncing
    requestAnimationFrame(() => {
      syncGridItems(pinnedMuuri.current, pinnedGridRef, pinnedNotes);
      syncGridItems(othersMuuri.current, othersGridRef, othersNotes);

      // CRITICAL: Force a second layout after CSS transitions (padding/height changes) complete
      // NoteCard has a 200ms transition. We wait 300ms to be safe.
      setTimeout(() => {
        if (pinnedMuuri.current) pinnedMuuri.current.refreshItems().layout();
        if (othersMuuri.current) othersMuuri.current.refreshItems().layout();
      }, 300);
    });
  }, [pinnedNotes, othersNotes, muuriReady]); // Re-run when notes change or Muuri becomes ready

  // Handle container resize to update responsive layout
  useEffect(() => {
    if (!containerRef.current || (!pinnedMuuri.current && !othersMuuri.current)) return;

    let resizeTimeout: NodeJS.Timeout;

    const handleResize = (entries: ResizeObserverEntry[]) => {
      clearTimeout(resizeTimeout);
      resizeTimeout = setTimeout(() => {
        // Get precise width from ResizeObserver
        const containerWidth = entries[0]?.contentRect.width || window.innerWidth - 32;
        const columns = calculateColumns(containerWidth);



        // Apply dimensions to both grids
        applyItemDimensions(pinnedMuuri.current, containerWidth);
        applyItemDimensions(othersMuuri.current, containerWidth);

        // Refresh layouts
        requestAnimationFrame(() => {
          pinnedMuuri.current?.refreshItems().layout();
          othersMuuri.current?.refreshItems().layout();
        });
      }, 150); // Debounce
    };

    const observer = new ResizeObserver(handleResize);
    observer.observe(containerRef.current);

    // Initial layout check
    if (containerRef.current) {
      handleResize([{ contentRect: containerRef.current.getBoundingClientRect() } as ResizeObserverEntry]);
    }

    return () => {
      clearTimeout(resizeTimeout);
      observer.disconnect();
    };
  }, [applyItemDimensions, muuriReady]);

  return (
    <div ref={containerRef} 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}
                onNoteSizeChange={handleNoteSizeChange}
                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}
                onNoteSizeChange={handleNoteSizeChange}
                onDragStart={startDrag}
                onDragEnd={endDrag}
                isDragging={draggedNoteId === note.id}
              />
            ))}
          </div>
        </div>
      )}

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

    </div>
  );
}
