import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';
import { LayoutStore, LayoutCard } from './LayoutSystem';
import DesktopDocumentCard from './DesktopDocumentCard';
import usePreviewMetadata from './hooks/usePreviewMetadata';
import useDeskTagInteractions from './tags/useDeskTagInteractions';
import { useCardPointer } from './useCardPointer';
import '../styles/workspace/workspace-layout.css';
import '../styles/workspace/workspace-items.css';
import '../styles/workspace/workspace-cards.css';
import { useWorkspaceSelectionContext } from '../app/WorkspaceSelectionContext';
import { createDocumentEntryKey } from '../app/entryKey';
import { PointerTrackingProvider, usePointerTracking } from './PointerTrackingContext';
import type { Identifier } from '../types/identifiers';
import type { DocumentsListEntry, Document } from '../types/documents';
import { usePreviewContext } from '../preview/PreviewContext';

type TagLike = { id?: Identifier | null; label?: string; color?: string | null } | null;
type OverlaySource = { url: string; alt?: string | null; mimeType?: string | null; };

export interface DeskDocument {
  id?: Identifier | null;
  title?: string;
  tags?: TagLike[] | null;
  documentLink?: OverlaySource | null;
  [key: string]: unknown;
}

interface DocumentSizeInfo {
  width: number;
  height: number;
  source?: 'snapshot' | 'metadata' | 'fallback';
}

// Fallback size computation
const computeFallbackCardSize = (_doc: DeskDocument): DocumentSizeInfo => {
  return { width: 200, height: 200, source: 'fallback' };
};

export interface DesktopWorkspaceProps {
  entries: DocumentsListEntry[];
  ensureAssetUrl?: (...args: any[]) => Promise<unknown>;
  getDocumentAsset?: (...args: any[]) => unknown;
  onDocumentActivate?: (doc: DeskDocument, event?: unknown) => void;
  onSelectionChange?: (selectedIds: Identifier[]) => void;
  onDocumentTagDrop?: (docId: Identifier, tag: any) => void;
  tenantId?: Identifier | null;
  viewId?: string | null;
}

// Wrapper to handle hooks per card
const DesktopDocumentContainer: React.FC<React.ComponentProps<typeof DesktopDocumentCard> & {
  onSelect: (ids: string[], extend?: boolean) => void;
  onDeselect: (ids: string[]) => void;
  onDocumentActivate?: (id: string) => void;
  selection: string[];
}> = React.memo((props) => {
  const { layoutCard, selected, onSelect, onDeselect, onDocumentActivate, selection } = props;

  // We assume layoutCard is always present in this context
  const cardPointerHandlers = useCardPointer(layoutCard!, !!selected, selection, onSelect, onDeselect, onDocumentActivate);

  return (
    <DesktopDocumentCard
      {...props}
      cardPointerHandlers={cardPointerHandlers}
    />
  );
});

DesktopDocumentContainer.displayName = 'DesktopDocumentContainer';

const DesktopWorkspaceContent: React.FC<DesktopWorkspaceProps> = ({
  entries,
  ensureAssetUrl,
  getDocumentAsset,
  onDocumentActivate,
  onSelectionChange,
  onDocumentTagDrop,
  tenantId,
  viewId,
}) => {
  const { openPreview } = usePreviewContext();
  const { addPointer, removePointer } = usePointerTracking();
  const containerRef = useRef<HTMLDivElement>(null);
  const [isLayoutReady, setIsLayoutReady] = useState(false);

  const items = useMemo(() => {
    return entries
      .filter((entry): entry is { type: 'document'; document: Document } & DocumentsListEntry =>
        entry.type === 'document' && !!entry.document
      )
      .map(entry => entry.document as DeskDocument);
  }, [entries]);

  // Layout System Initialization
  const layoutStore = useMemo(() => new LayoutStore(), []);
  const layoutRef = useRef<Map<string, LayoutCard>>(new Map());

  // Update container size in store
  useEffect(() => {
    if (!containerRef.current) return;

    const observer = new ResizeObserver((entries) => {
      for (const entry of entries) {
        const { width, height } = entry.contentRect;
        layoutStore.setContainerSize(width, height);
        if (width > 0 && height > 0) {
          setIsLayoutReady(true);
        }
      }
    });

    observer.observe(containerRef.current);
    return () => observer.disconnect();
  }, [layoutStore]);

  useEffect(() => {
    if (tenantId && viewId) {
      // Clear store when switching views to prevent stale items
      layoutStore.clear();
      layoutStore.loadLayout(String(tenantId), viewId);
    }
  }, [layoutStore, tenantId, viewId]);

  // Sync LayoutStore items with current entries to remove stale items
  useEffect(() => {
    const currentIds = new Set(items.map((doc, index) => doc.id ? String(doc.id) : `temp-${index}`));

    // Identify and remove items that are no longer present
    for (const id of layoutStore.items.keys()) {
      if (!currentIds.has(id)) {
        layoutStore.unregister(id);
      }
    }
  }, [items, layoutStore]);

  // Selection Context
  const {
    selectedDocumentIds,
    setSelectedEntries,
    clearSelection,
  } = useWorkspaceSelectionContext();

  const handleSelectionChange = useCallback((ids: Identifier[]) => {
    if (setSelectedEntries) {
      const keys = ids.map(id => createDocumentEntryKey(id));
      setSelectedEntries(keys);
    }
    onSelectionChange?.(ids);
  }, [setSelectedEntries, onSelectionChange]);

  const onClearSelection = useCallback(() => {
    clearSelection ? clearSelection() : handleSelectionChange([]);
  }, [clearSelection, handleSelectionChange]);

  const metadataMap = usePreviewMetadata(items, getDocumentAsset, ensureAssetUrl);

  const ensureDocumentSize = useCallback((doc: DeskDocument): DocumentSizeInfo => {
    if (doc.id) {
      const meta = metadataMap.get(String(doc.id));
      if (meta && meta.width && meta.height)
        return { width: meta.width, height: meta.height, source: 'metadata' };
    }

    return computeFallbackCardSize(doc);
  }, [metadataMap]);

  // Sync LayoutStore to layoutRef
  useEffect(() => {
    const sync = () => {
      layoutRef.current = layoutStore.items;
    };
    sync();
  }, [layoutStore.items]);

  const handleShellKeyDown = useCallback(() => { }, []);
  const focusShell = useCallback(() => { }, []);

  // Tag Interactions
  const [pendingRemovalTag, setPendingRemovalTag] = useState<{ docId?: string; tagId?: string } | null>(null);
  const [tagDropTargetId, setTagDropTargetId] = useState<string | null>(null);
  const [pendingTagDocId, setPendingTagDocId] = useState<string | null>(null);

  const tagEngine = useMemo(() => ({
    setPendingRemovalTag,
    setTagDropTargetId,
    setPendingTagDocId,
  }), []);

  const tagInteractions = useDeskTagInteractions({
    engine: tagEngine,
    onAssignTagToDocument: (docId: string, tag: any) => {
      onDocumentTagDrop?.(docId, tag);
    },
    requestCanvasFocus: focusShell,
  });

  useEffect(() => {
    const handleWindowKeyDown = (e: KeyboardEvent) => {
      if (e.code === 'Space' && selectedDocumentIds.length > 0) {
        // Preview the last selected document
        const lastId = selectedDocumentIds[selectedDocumentIds.length - 1];
        const doc = items.find(i => String(i.id) === lastId);
        if (doc) {
          e.preventDefault();
          openPreview(doc);
        }
      }
    };

    window.addEventListener('keydown', handleWindowKeyDown);
    return () => window.removeEventListener('keydown', handleWindowKeyDown);
  }, [selectedDocumentIds, items, openPreview]);

  return (
    <>
      <div
        className="desk-shell"
      >
        <div
          className="desk-canvas"
          ref={containerRef}
          tabIndex={0}
          onKeyDown={handleShellKeyDown}
          onPointerDown={(e) => {
            if (e.target === e.currentTarget) {
              // Register background pointer
              addPointer(e.pointerId);
              (e.target as Element).setPointerCapture(e.pointerId);

              onClearSelection();
              focusShell();
            }
          }}
          onPointerUp={(e) => {
            if (e.target === e.currentTarget) {
              removePointer(e.pointerId);
              (e.target as Element).releasePointerCapture(e.pointerId);
            }
          }}
          onPointerCancel={(e) => {
            if (e.target === e.currentTarget) {
              removePointer(e.pointerId);
              (e.target as Element).releasePointerCapture(e.pointerId);
            }
          }}
        >
          {isLayoutReady && items.map((doc, index) => {
            const docId = doc.id ? String(doc.id) : `temp-${index}`;
            const isSelected = selectedDocumentIds.includes(docId);
            const size = ensureDocumentSize(doc);

            const layoutCard = layoutStore.initialize(docId, null, {
              width: Number.isFinite(size.width) && size.width > 0 ? size.width : 200,
              height: Number.isFinite(size.height) && size.height > 0 ? size.height : 200
            });

            return (
              <DesktopDocumentContainer
                key={docId}
                doc={doc}
                style={{
                  position: 'absolute',
                  top: 0,
                  left: 0,
                  touchAction: 'none',
                  willChange: 'transform'
                }}
                shouldLoad={true}
                matchesFilter={true}

                selected={isSelected}
                docTagTokens=""
                ensureAssetUrl={ensureAssetUrl}
                getDocumentAsset={getDocumentAsset}
                handleNavigatorSnapshot={() => { }}
                onDocumentActivate={(id) => { onDocumentActivate?.({ id } as DeskDocument) }}
                layoutCard={layoutCard}
                onTagDragEnter={tagInteractions.handleTagDragEnterDoc}
                onTagDragOver={tagInteractions.handleTagDragOverDoc}
                onTagDragLeave={tagInteractions.handleTagDragLeaveDoc}
                onTagDrop={tagInteractions.handleTagDropOnDoc}
                onDocTagPointerDown={tagInteractions.handleDocTagPointerDown}
                onDocTagDragStart={tagInteractions.handleDocTagDragStart}
                onDocTagDrag={tagInteractions.handleDocTagDrag}
                onDocTagDragEnd={tagInteractions.handleDocTagDragEnd}
                tagTargetActive={tagDropTargetId === docId}
                tagTargetPending={pendingTagDocId === docId}
                pendingRemovalTag={pendingRemovalTag}
                onSelect={(ids, extend = false) => {
                  if (!extend) {
                    handleSelectionChange(ids);
                  } else {
                    const newSelection = new Set(selectedDocumentIds);
                    ids.forEach(id => newSelection.add(id));
                    handleSelectionChange(Array.from(newSelection));
                  }
                }}
                onDeselect={(ids) => {
                  const newSelection = new Set(selectedDocumentIds);
                  ids.forEach(id => newSelection.delete(id));
                  handleSelectionChange(Array.from(newSelection));
                }}
                selection={selectedDocumentIds}
              />
            );
          })}
        </div>
      </div>
    </>
  );
};

const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = (props) => {
  return (
    <PointerTrackingProvider>
      <DesktopWorkspaceContent {...props} />
    </PointerTrackingProvider>
  );
};

export default DesktopWorkspace;
