"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/store/workflowStore";
import type {
  GenerateVideoNodeData,
  NanoBananaNodeData,
  ProviderType,
  WorkflowNode,
} from "@/types";
import { MediaPreviewModal } from "@/components/MediaPreviewModal";

type WorkflowGenerationHistoryItem = {
  key: string;
  id: string;
  nodeId: string;
  historyIndex: number;
  mediaType: "image" | "video";
  mediaUrl?: string;
  coverUrl?: string;
  timestamp: number;
  prompt: string;
  model: string;
  modelDisplayName?: string;
  modelProvider?: ProviderType;
};

function formatRelativeTime(timestamp: number): string {
  const diff = Date.now() - timestamp;
  const seconds = Math.floor(diff / 1000);
  const minutes = Math.floor(seconds / 60);
  const hours = Math.floor(minutes / 60);

  if (hours > 0) return `${hours}h ago`;
  if (minutes > 0) return `${minutes}m ago`;
  return "Just now";
}

function calculateFanPosition(index: number) {
  const verticalSpacing = 60;
  const curveStrength = 0.15;
  return {
    x: -28 + index * index * curveStrength,
    y: -(index * verticalSpacing + 56),
  };
}

export function collectWorkflowGenerationHistory(nodes: WorkflowNode[]): WorkflowGenerationHistoryItem[] {
  const items: WorkflowGenerationHistoryItem[] = [];

  nodes.forEach((node) => {
    if (node.type === "nanoBanana" || node.type === "smartImage") {
      const data = node.data as NanoBananaNodeData;
      (data.imageHistory || []).forEach((item, historyIndex) => {
        items.push({
          key: `${node.id}:image:${item.id}:${historyIndex}`,
          id: item.id,
          nodeId: node.id,
          historyIndex,
          mediaType: "image",
          mediaUrl: item.image ?? item.previewImg,
          timestamp: item.timestamp,
          prompt: item.prompt,
          model: item.model,
          modelDisplayName: item.modelDisplayName,
          modelProvider: item.modelProvider,
        });
      });
    }

    if (node.type === "generateVideo" || node.type === "smartVideo") {
      const data = node.data as GenerateVideoNodeData;
      (data.videoHistory || []).forEach((item, historyIndex) => {
        items.push({
          key: `${node.id}:video:${item.id}:${historyIndex}`,
          id: item.id,
          nodeId: node.id,
          historyIndex,
          mediaType: "video",
          mediaUrl: item.video,
          coverUrl: item.videoCover,
          timestamp: item.timestamp,
          prompt: item.prompt,
          model: item.model,
          modelDisplayName: item.modelDisplayName,
          modelProvider: item.modelProvider,
        });
      });
    }
  });

  return items.sort((a, b) => b.timestamp - a.timestamp);
}

function MediaThumb({
  item,
  src,
  className,
}: {
  item: WorkflowGenerationHistoryItem;
  src?: string;
  className: string;
}) {
  if (!src) {
    return (
      <div className={`${className} flex items-center justify-center bg-neutral-900 text-[10px] text-neutral-500`}>
        {item.mediaType === "video" ? "Video" : "Image"}
      </div>
    );
  }

  if (item.mediaType === "video" && item.coverUrl) {
    return (
      <img
        src={item.coverUrl}
        alt=""
        className={className}
        draggable={false}
      />
    );
  }

  return item.mediaType === "video" ? (
    <video
      src={src}
      muted
      loop
      playsInline
      preload="metadata"
      className={className}
      draggable={false}
    />
  ) : (
    <img
      src={src}
      alt=""
      className={className}
      draggable={false}
    />
  );
}

function FanItem({
  item,
  mediaSrc,
  index,
  onDragStart,
  onPreview,
}: {
  item: WorkflowGenerationHistoryItem;
  mediaSrc?: string;
  index: number;
  onDragStart: (event: React.DragEvent, item: WorkflowGenerationHistoryItem, mediaSrc?: string) => void;
  onPreview: (item: WorkflowGenerationHistoryItem, mediaSrc?: string) => void;
}) {
  const { x, y } = calculateFanPosition(index);

  return (
    <div
      draggable={Boolean(mediaSrc)}
      onDragStart={(event) => onDragStart(event, item, mediaSrc)}
      onDoubleClick={(event) => {
        event.preventDefault();
        event.stopPropagation();
        onPreview(item, mediaSrc);
      }}
      className="group absolute h-14 w-14 cursor-grab overflow-hidden rounded-lg border-2 border-neutral-600 shadow-lg transition-colors duration-150 animate-fan-enter hover:border-blue-500 active:cursor-grabbing"
      style={
        {
          "--fan-x": `${x}px`,
          "--fan-y": `${y}px`,
          animationDelay: `${index * 30}ms`,
          zIndex: 10 - index,
        } as React.CSSProperties
      }
      title={`${formatRelativeTime(item.timestamp)}${item.modelDisplayName ? `\n${item.modelDisplayName}` : ""}\n${item.prompt?.substring(0, 50) || ""}...`}
    >
      <MediaThumb item={item} src={mediaSrc} className="h-full w-full object-cover pointer-events-none" />
      {item.mediaType === "video" && (
        <span className="pointer-events-none absolute bottom-1 left-1 rounded bg-black/70 px-1 text-[9px] text-white">
          VID
        </span>
      )}
    </div>
  );
}

function HistorySidebar({
  history,
  onClose,
  onDragStart,
  onPreview,
  triggerRect,
}: {
  history: WorkflowGenerationHistoryItem[];
  onClose: () => void;
  onDragStart: (event: React.DragEvent, item: WorkflowGenerationHistoryItem, mediaSrc?: string) => void;
  onPreview: (item: WorkflowGenerationHistoryItem, mediaSrc?: string) => void;
  triggerRect: DOMRect | null;
}) {
  const sidebarRef = useRef<HTMLDivElement>(null);
  const viewportMargin = 16;
  const sidebarGap = 8;
  const sidebarWidth = Math.min(320, window.innerWidth - viewportMargin * 2);

  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (sidebarRef.current && !sidebarRef.current.contains(event.target as Node)) {
        onClose();
      }
    };
    document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, [onClose]);

  useEffect(() => {
    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") onClose();
    };
    document.addEventListener("keydown", handleKeyDown);
    return () => document.removeEventListener("keydown", handleKeyDown);
  }, [onClose]);

  const sidebarStyle: React.CSSProperties = {
    position: "fixed",
    width: `${sidebarWidth}px`,
    maxHeight: "min(520px, calc(100vh - 32px))",
    zIndex: 200,
  };

  if (triggerRect) {
    const preferredLeft = triggerRect.right - sidebarWidth;
    const maxLeft = window.innerWidth - sidebarWidth - viewportMargin;
    sidebarStyle.left = `${Math.max(viewportMargin, Math.min(preferredLeft, maxLeft))}px`;
    sidebarStyle.bottom = `${window.innerHeight - triggerRect.top + sidebarGap}px`;
    sidebarStyle.maxHeight = `${Math.max(
      240,
      Math.min(520, triggerRect.top - viewportMargin - sidebarGap)
    )}px`;
  } else {
    sidebarStyle.right = "100px";
    sidebarStyle.bottom = "100px";
  }

  return createPortal(
    <div
      ref={sidebarRef}
      className="flex flex-col rounded-lg border border-neutral-600 bg-neutral-800 shadow-xl"
      style={sidebarStyle}
    >
      <div className="flex shrink-0 items-center justify-between border-b border-neutral-700 px-4 py-3">
        <span className="text-sm font-medium text-neutral-200">
          Generated Media ({history.length})
        </span>
        <button
          type="button"
          onClick={onClose}
          className="flex h-5 w-5 items-center justify-center rounded text-neutral-400 transition-colors hover:bg-neutral-700 hover:text-white"
          title="Close"
        >
          <svg className="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
            <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
          </svg>
        </button>
      </div>

      <div className="flex-1 space-y-1.5 overflow-y-auto p-2">
        {history.map((item, index) => {
          const mediaSrc = item.mediaUrl;
          return (
            <div
              key={item.key}
              draggable={Boolean(mediaSrc)}
              onDragStart={(event) => onDragStart(event, item, mediaSrc)}
              onDoubleClick={(event) => {
                event.preventDefault();
                event.stopPropagation();
                onPreview(item, mediaSrc);
              }}
              className="group flex cursor-grab gap-3 rounded-lg p-2 transition-colors hover:bg-neutral-700/50 active:cursor-grabbing"
            >
              <div className="h-14 w-14 shrink-0 overflow-hidden rounded border border-neutral-600 transition-colors group-hover:border-blue-500">
                <MediaThumb item={item} src={mediaSrc} className="h-full w-full object-cover pointer-events-none" />
              </div>

              <div className="flex min-w-0 flex-1 flex-col justify-center">
                <p className="truncate text-[11px] text-neutral-300">
                  {item.prompt?.substring(0, 60) || "No prompt"}
                </p>
                <p className="mt-0.5 text-[10px] text-neutral-500">
                  {formatRelativeTime(item.timestamp)} · {item.mediaType === "video" ? "Video" : "Image"} · {item.modelDisplayName || item.model}
                </p>
              </div>

              <span className="sr-only">History {index + 1}</span>
            </div>
          );
        })}
      </div>

      <div className="shrink-0 border-t border-neutral-700 bg-neutral-900/50 px-4 py-2">
        <span className="text-[10px] text-neutral-500">Drag media to canvas to create nodes</span>
      </div>
    </div>,
    document.body
  );
}

type GlobalImageHistoryProps = {
  placement?: "floating" | "inline";
  className?: string;
};

export function GlobalImageHistory({
  placement = "floating",
  className = "",
}: GlobalImageHistoryProps) {
  const [isOpen, setIsOpen] = useState(false);
  const [showSidebar, setShowSidebar] = useState(false);
  const [previewItem, setPreviewItem] = useState<{
    item: WorkflowGenerationHistoryItem;
    src: string;
  } | null>(null);
  const drawerRef = useRef<HTMLDivElement>(null);
  const triggerRef = useRef<HTMLButtonElement>(null);

  const { nodes } = useWorkflowStore(useShallow((state) => ({
    nodes: state.nodes,
  })));

  const history = useMemo(() => collectWorkflowGenerationHistory(nodes), [nodes]);
  const fanItems = history.slice(0, 10);
  const hasOverflow = history.length > 10;

  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (drawerRef.current && !drawerRef.current.contains(event.target as Node)) {
        setIsOpen(false);
      }
    };

    if (isOpen && !showSidebar) {
      document.addEventListener("mousedown", handleClickOutside);
    }
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, [isOpen, showSidebar]);

  useEffect(() => {
    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        if (showSidebar) {
          setShowSidebar(false);
        } else {
          setIsOpen(false);
        }
      }
    };
    if (isOpen || showSidebar) {
      document.addEventListener("keydown", handleKeyDown);
    }
    return () => document.removeEventListener("keydown", handleKeyDown);
  }, [isOpen, showSidebar]);

  const handleDragStart = useCallback(
    (event: React.DragEvent, item: WorkflowGenerationHistoryItem, mediaSrc?: string) => {
      if (!mediaSrc) {
        event.preventDefault();
        return;
      }

      const payload = JSON.stringify({
        [item.mediaType]: mediaSrc,
        ...(item.mediaType === "video" && item.coverUrl ? { cover: item.coverUrl } : {}),
        prompt: item.prompt,
        timestamp: item.timestamp,
      });
      event.dataTransfer.setData(
        item.mediaType === "video" ? "application/history-video" : "application/history-image",
        payload
      );
      event.dataTransfer.effectAllowed = "copy";

      setTimeout(() => {
        setIsOpen(false);
        setShowSidebar(false);
      }, 0);
    },
    []
  );

  const handlePreview = useCallback((item: WorkflowGenerationHistoryItem, mediaSrc?: string) => {
    if (!mediaSrc) return;
    setPreviewItem({ item, src: mediaSrc });
  }, []);

  if (history.length === 0) return null;

  const placementClass =
    placement === "inline"
      ? "relative z-10"
      : "absolute bottom-4 right-10 z-30";

  return (
    <div ref={drawerRef} className={`nodrag nopan nowheel ${placementClass} ${className}`}>
      <button
        ref={triggerRef}
        type="button"
        onClick={() => setIsOpen(!isOpen)}
        className="relative flex h-8 w-8 items-center justify-center rounded-lg border border-neutral-600 bg-neutral-800 text-neutral-400 shadow-lg transition-colors hover:bg-neutral-700 hover:text-white"
        title={`${history.length} generated media item${history.length > 1 ? "s" : ""}`}
      >
        <svg
          className="h-4 w-4"
          fill="none"
          viewBox="0 0 24 24"
          stroke="currentColor"
          strokeWidth={2}
        >
          <path
            strokeLinecap="round"
            strokeLinejoin="round"
            d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
          />
        </svg>
        <span className="absolute -right-1.5 -top-1.5 flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-blue-500 px-1 text-[10px] font-bold text-white">
          {history.length > 99 ? "99+" : history.length}
        </span>
      </button>

      {isOpen && (
        <div className="absolute bottom-full right-1/2 mb-2 translate-x-1/2" style={{ zIndex: 100 }}>
          <div className="relative h-0 w-0">
            {fanItems.map((item, index) => (
              <FanItem
                key={item.key}
                item={item}
                mediaSrc={item.mediaUrl}
                index={index}
                onDragStart={handleDragStart}
                onPreview={handlePreview}
              />
            ))}
          </div>

          {hasOverflow && (() => {
            const topItemPos = calculateFanPosition(fanItems.length - 1);
            return (
              <button
                type="button"
                onClick={() => {
                  setIsOpen(false);
                  setShowSidebar(true);
                }}
                className="absolute animate-fan-enter whitespace-nowrap rounded-lg border border-neutral-600 bg-neutral-800 px-2 py-1 text-[10px] text-neutral-300 shadow-lg transition-colors hover:bg-neutral-700 hover:text-white"
                style={
                  {
                    "--fan-x": `${topItemPos.x}px`,
                    "--fan-y": `${topItemPos.y - 60}px`,
                    animationDelay: `${fanItems.length * 30}ms`,
                  } as React.CSSProperties
                }
              >
                +{history.length - 10} more
              </button>
            );
          })()}
        </div>
      )}

      {showSidebar && (
        <HistorySidebar
          history={history}
          onClose={() => setShowSidebar(false)}
          onDragStart={handleDragStart}
          onPreview={handlePreview}
          triggerRect={triggerRef.current?.getBoundingClientRect() || null}
        />
      )}

      {previewItem && (
        <MediaPreviewModal
          type={previewItem.item.mediaType}
          src={previewItem.src}
          downloadSrc={previewItem.src}
          alt="Generated media preview"
          onClose={() => setPreviewItem(null)}
        />
      )}
    </div>
  );
}
