import React, { useEffect, useState, useRef, useCallback } from 'react';
import clsx from 'clsx';
import {
  fetchSessions, createSession, deleteSession, updateSession,
  fetchFolders, createFolder, deleteFolder, updateFolder,
  type ChatSession, type ChatFolder,
} from '@/api/ai';

interface SessionListProps {
  activeSessionId: string | null;
  onSelectSession: (id: string) => void;
  isSidebar?: boolean;
  className?: string;
}

interface TreeNode {
  folder: ChatFolder | null;
  sessions: ChatSession[];
  children: TreeNode[];
}

interface ContextMenuState {
  x: number;
  y: number;
  type: 'session' | 'folder' | 'root';
  id: string | null;
}

function buildTree(folders: ChatFolder[], sessions: ChatSession[]): TreeNode[] {
  const rootSessions = sessions.filter((s) => !s.folder_id);
  const root: TreeNode = { folder: null, sessions: rootSessions, children: [] };
  const folderMap = new Map<string, TreeNode>();
  for (const f of folders) folderMap.set(f.id, { folder: f, sessions: [], children: [] });
  for (const f of folders) {
    const node = folderMap.get(f.id)!;
    if (f.parent_id && folderMap.has(f.parent_id)) folderMap.get(f.parent_id)!.children.push(node);
    else root.children.push(node);
  }
  for (const s of sessions) {
    if (s.folder_id && folderMap.has(s.folder_id)) folderMap.get(s.folder_id)!.sessions.push(s);
  }
  return [root];
}

function TreeItem({
  node, activeSessionId, onSelectSession, depth, onContextMenu, onDragSession, onDragFolder, onDropToFolder, onDelete, onRename,
}: {
  node: TreeNode;
  activeSessionId: string | null;
  onSelectSession: (id: string) => void;
  depth: number;
  onContextMenu: (e: React.MouseEvent, type: 'session' | 'folder' | 'root', id: string | null) => void;
  onDragSession: (sessionId: string) => void;
  onDragFolder: (folderId: string) => void;
  onDropToFolder: (folderId: string | null) => void;
  onDelete: (id: string, type: 'session' | 'folder') => void;
  onRename: (id: string, type: 'session' | 'folder') => void;
}) {
  const [expanded, setExpanded] = useState(true);
  const [isDragOver, setIsDragOver] = useState(false);
  const isRoot = node.folder === null;
  const folderId = node.folder?.id || null;

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragOver(false);
    const data = e.dataTransfer.getData('text/plain');
    if (data.startsWith('folder:')) {
      const draggedFolderId = data.slice(7);
      if (draggedFolderId !== folderId) {
        onDropToFolder(folderId);
      }
    } else {
      onDropToFolder(folderId);
    }
  };

  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    if (!isRoot) setIsDragOver(true);
  };

  return (
    <div>
      {/* Folder header - drop target */}
      {!isRoot && (
        <div
          onDragOver={handleDragOver}
          onDragLeave={() => setIsDragOver(false)}
          onDrop={handleDrop}
          onContextMenu={(e) => onContextMenu(e, 'folder', node.folder!.id)}
          className={clsx(
            'group flex items-center gap-1 px-2 py-1.5 text-sm font-medium rounded-md cursor-pointer',
            isDragOver ? 'bg-primary-100 ring-2 ring-primary-400' : 'text-secondary-700 hover:bg-secondary-100'
          )}
          style={{ paddingLeft: depth * 12 + 8 }}
          onClick={() => setExpanded(!expanded)}
        >
          <svg className={clsx('w-4 h-4 transition-transform', expanded && 'rotate-90')} fill="none" viewBox="0 0 24 24" stroke="currentColor">
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
          </svg>
          <span
            draggable
            onDragStart={(e) => {
              e.dataTransfer.setData('text/plain', `folder:${node.folder!.id}`);
              e.dataTransfer.effectAllowed = 'move';
              onDragFolder(node.folder!.id);
            }}
            className="cursor-grab active:cursor-grabbing flex items-center"
            title="Ordner verschieben"
          >
            <svg className="w-4 h-4 text-secondary-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
            </svg>
          </span>
          <span className="flex-1 truncate">{node.folder!.name}</span>
              <button onClick={(e) => { e.stopPropagation(); onRename(node.folder!.id, 'folder'); }} className="opacity-0 group-hover:opacity-100 text-secondary-400 hover:text-primary-600 p-0.5" title="Umbenennen">
                <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" /></svg>
              </button>
              <button onClick={(e) => { e.stopPropagation(); onDelete(node.folder!.id, 'folder'); }} className="opacity-0 group-hover:opacity-100 text-secondary-400 hover:text-red-600 p-0.5" title="Löschen">
                <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /></svg>
              </button>
        </div>
      )}

      {/* Sessions */}
      {(isRoot || expanded) && (
        <div>
          {node.sessions.map((session) => (
            <div
              key={session.id}
              draggable
              onDragStart={(e) => {
                e.dataTransfer.setData('text/plain', session.id);
                e.dataTransfer.effectAllowed = 'move';
                onDragSession(session.id);
              }}
              onContextMenu={(e) => onContextMenu(e, 'session', session.id)}
              onClick={() => onSelectSession(session.id)}
              className={clsx(
                'group flex items-center gap-2 px-3 py-1.5 text-sm cursor-pointer rounded-md',
                'hover:bg-secondary-100',
                activeSessionId === session.id && 'bg-primary-50'
              )}
              style={{ paddingLeft: depth * 12 + 24 }}
            >
              <svg className="w-3.5 h-3.5 text-secondary-400 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 12h8M8 8h8m-8 4h8m-8 4h8" />
              </svg>
              <span className={clsx('flex-1 truncate', activeSessionId === session.id && 'font-bold text-primary-700')}>
                {session.title}
              </span>
              <button onClick={(e) => { e.stopPropagation(); onRename(session.id, 'session'); }} className="opacity-0 group-hover:opacity-100 text-secondary-400 hover:text-primary-600 p-0.5" title="Umbenennen">
                <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" /></svg>
              </button>
              <button onClick={(e) => { e.stopPropagation(); onDelete(session.id, 'session'); }} className="opacity-0 group-hover:opacity-100 text-secondary-400 hover:text-red-600 p-0.5" title="Löschen">
                <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /></svg>
              </button>
            </div>
          ))}
        </div>
      )}

      {/* Root drop zone */}
      {isRoot && (
        <div
          onDragOver={handleDragOver}
          onDragLeave={() => setIsDragOver(false)}
          onDrop={handleDrop}
          onContextMenu={(e) => onContextMenu(e, 'root', null)}
          className={clsx(
            'min-h-[12px] mt-1 rounded-md transition-colors',
            isDragOver ? 'bg-primary-50 ring-1 ring-primary-300' : 'hover:bg-secondary-50'
          )}
        />
      )}

      {/* Child folders */}
      {(isRoot || expanded) && node.children.map((child) => (
        <TreeItem
          key={child.folder!.id}
          node={child}
          activeSessionId={activeSessionId}
          onSelectSession={onSelectSession}
          depth={depth + 1}
          onContextMenu={onContextMenu}
          onDragSession={onDragSession}
          onDragFolder={onDragFolder}
          onDropToFolder={onDropToFolder}
          onDelete={onDelete}
          onRename={onRename}
        />
      ))}
    </div>
  );
}

function ContextMenu({
  state, onClose, onRename, onDelete, onNewFolder, onNewChat,
}: {
  state: ContextMenuState;
  onClose: () => void;
  onRename: (id: string, type: 'session' | 'folder') => void;
  onDelete: (id: string, type: 'session' | 'folder') => void;
  onNewFolder: () => void;
  onNewChat: () => void;
}) {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const handler = (e: MouseEvent) => {
      if (ref.current && !ref.current.contains(e.target as Node)) onClose();
    };
    document.addEventListener('mousedown', handler);
    return () => document.removeEventListener('mousedown', handler);
  }, [onClose]);

  const items: { label: string; action: () => void; danger?: boolean }[] = [];

  if (state.type === 'session') {
    items.push({ label: 'Umbenennen', action: () => { onRename(state.id!, 'session'); onClose(); } });
    items.push({ label: 'Löschen', action: () => { onDelete(state.id!, 'session'); onClose(); }, danger: true });
  } else if (state.type === 'folder') {
    items.push({ label: 'Umbenennen', action: () => { onRename(state.id!, 'folder'); onClose(); } });
    items.push({ label: 'Neuer Unterordner', action: () => { onClose(); /* TODO */ } });
    items.push({ label: 'Löschen', action: () => { onDelete(state.id!, 'folder'); onClose(); }, danger: true });
  } else {
    items.push({ label: 'Neuer Chat', action: () => { onNewChat(); onClose(); } });
    items.push({ label: 'Neuer Ordner', action: () => { onNewFolder(); onClose(); } });
  }

  return (
    <div
      ref={ref}
      className="fixed z-50 bg-white border border-secondary-200 rounded-lg shadow-lg py-1 min-w-[160px]"
      style={{ left: state.x, top: state.y }}
    >
      {items.map((item, i) => (
        <button
          key={i}
          onClick={item.action}
          className={clsx(
            'w-full text-left px-3 py-1.5 text-sm hover:bg-secondary-100',
            item.danger && 'text-red-600 hover:bg-red-50'
          )}
        >
          {item.label}
        </button>
      ))}
    </div>
  );
}

export function SessionList({ activeSessionId, onSelectSession, isSidebar, className }: SessionListProps) {
  const [sessions, setSessions] = useState<ChatSession[]>([]);
  const [folders, setFolders] = useState<ChatFolder[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [dragSessionId, setDragSessionId] = useState<string | null>(null);
  const [dragFolderId, setDragFolderId] = useState<string | null>(null);
  const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);

  const loadData = async () => {
    try {
      setLoading(true);
      const [s, f] = await Promise.all([fetchSessions(isSidebar ? true : undefined), fetchFolders()]);
      setSessions(s); setFolders(f); setError(null);
    } catch (e) { setError(e instanceof Error ? e.message : 'Failed to load'); }
    finally { setLoading(false); }
  };

  useEffect(() => { loadData(); }, [isSidebar]);

  const handleContextMenu = useCallback((e: React.MouseEvent, type: 'session' | 'folder' | 'root', id: string | null) => {
    e.preventDefault();
    e.stopPropagation();
    setContextMenu({ x: e.clientX, y: e.clientY, type, id });
  }, []);

  const handleRename = async (id: string, type: 'session' | 'folder') => {
    const newName = prompt('Neuer Name:', type === 'session'
      ? sessions.find(s => s.id === id)?.title || ''
      : folders.find(f => f.id === id)?.name || ''
    );
    if (!newName) return;
    try {
      if (type === 'session') await updateSession(id, { title: newName });
      else await updateFolder(id, { name: newName });
      loadData();
    } catch (e) { setError(e instanceof Error ? e.message : 'Rename failed'); }
  };

  const handleDelete = async (id: string, type: 'session' | 'folder') => {
    if (!confirm(type === 'session' ? 'Chat löschen?' : 'Ordner löschen? Chats bleiben erhalten.')) return;
    try {
      if (type === 'session') {
        await deleteSession(id);
        if (activeSessionId === id) onSelectSession('');
      } else {
        await deleteFolder(id);
      }
      loadData();
    } catch (e) { setError(e instanceof Error ? e.message : 'Delete failed'); }
  };

  const handleNewFolder = () => {
    const name = prompt('Ordnername:');
    if (!name) return;
    createFolder({ name }).then(() => loadData()).catch((e) => setError(e?.message));
  };

  const handleNewChat = async () => {
    try {
      const session = await createSession({ is_sidebar: isSidebar || false });
      onSelectSession(session.id);
      loadData();
    } catch (e) { setError(e instanceof Error ? e.message : 'Failed'); }
  };

  const handleDropToFolder = async (folderId: string | null) => {
    if (dragFolderId) {
      try {
        await updateFolder(dragFolderId, { parent_id: folderId });
        setDragFolderId(null);
        loadData();
      } catch (e) { setError(e instanceof Error ? e.message : 'Failed to move folder'); }
      return;
    }
    if (!dragSessionId) return;
    try {
      await updateSession(dragSessionId, { folder_id: folderId });
      setDragSessionId(null);
      loadData();
    } catch (e) { setError(e instanceof Error ? e.message : 'Failed to move'); }
  };

  if (loading) return <div className="p-4 text-sm text-secondary-400">Laden...</div>;

  const tree = buildTree(folders, sessions);

  return (
    <div className={clsx('flex flex-col h-full', className)}>
      {error && <div className="p-2 text-xs text-red-600">{error}</div>}
      <div
        className="flex-1 overflow-y-auto p-2"
        onContextMenu={(e) => {
          if (e.target === e.currentTarget) handleContextMenu(e, 'root', null);
        }}
      >
        {tree.map((node) => (
          <TreeItem
            key={node.folder?.id || 'root'}
            node={node}
            activeSessionId={activeSessionId}
            onSelectSession={onSelectSession}
            depth={0}
            onContextMenu={handleContextMenu}
            onDragSession={setDragSessionId}
            onDragFolder={setDragFolderId}
            onDropToFolder={handleDropToFolder}
            onDelete={handleDelete}
            onRename={handleRename}
          />
        ))}
      </div>
      {contextMenu && (
        <ContextMenu
          state={contextMenu}
          onClose={() => setContextMenu(null)}
          onRename={handleRename}
          onDelete={handleDelete}
          onNewFolder={handleNewFolder}
          onNewChat={handleNewChat}
        />
      )}
    </div>
  );
}
