import { useState } from 'react'
import {
  ChevronRight,
  ChevronDown,
  Folder,
  Image,
  Star,
  Trash2,
  Plus,
  MoreHorizontal,
  HardDrive,
  RefreshCw,
} from 'lucide-react'
import clsx from 'clsx'
import { AddSourceFolderDialog } from '../dialogs/AddSourceFolderDialog'
import { sourceFolders, library, photos as photosApi } from '../../services/api'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { toast } from '../ToastContainer'
import { useFilterStore } from '../../store/filterStore'
import { HeapsPanel } from '../heaps/HeapsPanel'
import { PHOTO_DRAG_MIME } from '../timeline/PhotoThumbnail'

interface TreeItem {
  id: string
  label: string
  icon?: React.ReactNode
  count?: number
  children?: TreeItem[]
  type?: 'folder' | 'heap' | 'special'
}

export function LeftSidebar() {
  const [expandedItems, setExpandedItems] = useState<Set<string>>(new Set(['library', 'folders', 'heaps']))
  const [selectedItem, setSelectedItem] = useState<string | null>('all-photos')
  const [showAddFolderDialog, setShowAddFolderDialog] = useState(false)
  const [isScanning, setIsScanning] = useState(false)

  const queryClient = useQueryClient()
  const clearAllFilters = useFilterStore((s) => s.clearAll)
  const setRatingMin = useFilterStore((s) => s.setRatingMin)
  const setFlag = useFilterStore((s) => s.setFlag)
  const setFolderId = useFilterStore((s) => s.setFolderId)
  const filterFolderId = useFilterStore((s) => s.folderId)
  const [dropTargetId, setDropTargetId] = useState<string | null>(null)

  // Bulk discard mutation for the drag-onto-Discarded interaction.
  const discardDropMutation = useMutation({
    mutationFn: (photoIds: string[]) => photosApi.bulkDiscard(photoIds),
    onSuccess: (_data, photoIds) => {
      toast.success(
        'Discarded',
        `${photoIds.length} photo${photoIds.length > 1 ? 's' : ''}`
      )
      queryClient.invalidateQueries({ queryKey: ['photos'] })
    },
    onError: (e: any) =>
      toast.error('Discard failed', e?.message || 'Unknown error'),
  })

  // Bulk move mutation for the drag-onto-folder interaction.
  const moveDropMutation = useMutation({
    mutationFn: ({ targetId, photoIds }: { targetId: string; photoIds: string[] }) =>
      photosApi.move(photoIds, targetId),
    onSuccess: (data) => {
      const moved = data?.moved ?? 0
      const errCount = (data?.errors?.length ?? 0)
      if (moved > 0) {
        toast.success(
          'Moved',
          `${moved} photo${moved > 1 ? 's' : ''}${errCount ? ` (${errCount} skipped)` : ''}`
        )
      } else if (errCount > 0) {
        toast.error('Move failed', `${errCount} file${errCount > 1 ? 's' : ''} could not be moved`)
      }
      queryClient.invalidateQueries({ queryKey: ['photos'] })
      queryClient.invalidateQueries({ queryKey: ['folders'] })
    },
    onError: (e: any) =>
      toast.error('Move failed', e?.response?.data?.detail || e.message || 'Unknown error'),
  })

  // Reads the dragged ids out of a drop event payload.
  const readDragIds = (e: React.DragEvent): string[] | null => {
    const raw = e.dataTransfer.getData(PHOTO_DRAG_MIME)
    if (!raw) return null
    try {
      const parsed = JSON.parse(raw) as string[]
      return Array.isArray(parsed) && parsed.length > 0 ? parsed : null
    } catch {
      return null
    }
  }

  // Map a library tree id to a filter-store mutation. Each "virtual node" in
  // the library tree is just a saved filter preset.
  const applyLibraryNode = (id: string) => {
    switch (id) {
      case 'all-photos':
        clearAllFilters()
        break
      case 'rated':
        clearAllFilters()
        setRatingMin(1)
        break
      case 'discarded':
        clearAllFilters()
        setFlag('discarded')
        break
      default:
        if (id.startsWith('folder-')) {
          // Folder rows: filter to that folder, clear other filters that
          // would compete (heap, discarded, etc.) so the user sees what they
          // expect when they click a folder.
          const folderId = id.slice('folder-'.length)
          clearAllFilters()
          setFolderId(folderId)
        }
    }
  }
  
  // Fetch folders from API
  const { data: foldersData, refetch: refetchFolders } = useQuery({
    queryKey: ['folders'],
    queryFn: sourceFolders.list,
  })
  
  // Mutation for adding folders
  const addFolderMutation = useMutation({
    mutationFn: async ({ path, recursive }: { path: string; recursive: boolean }) => {
      // Add the folder
      const folder = await sourceFolders.add(path, recursive)
      // Trigger scan for the new folder
      await sourceFolders.scan(folder.id)
      return folder
    },
    onSuccess: (folder) => {
      toast.success('Folder Added', `Scanning ${folder.name || folder.path}...`)
      // Refetch folders list
      refetchFolders()
      // Refetch photos to show new ones
      queryClient.invalidateQueries({ queryKey: ['photos'] })
    },
    onError: (error: any) => {
      toast.error('Failed to Add Folder', error.message || 'An error occurred')
    },
  })
  
  // Mutation for scanning all folders
  const scanLibraryMutation = useMutation({
    mutationFn: library.scan,
    onMutate: () => {
      setIsScanning(true)
      toast.info('Scan Started', 'Scanning all folders for new photos...')
    },
    onSuccess: () => {
      toast.success('Scan Complete', 'All folders have been scanned')
    },
    onError: (error: any) => {
      toast.error('Scan Failed', error.message || 'Failed to scan folders')
    },
    onSettled: () => {
      setIsScanning(false)
      // Refetch photos after scan
      queryClient.invalidateQueries({ queryKey: ['photos'] })
    },
  })
  
  const handleAddFolder = async (path: string, recursive: boolean) => {
    await addFolderMutation.mutateAsync({ path, recursive })
  }
  
  const handleScanAll = () => {
    scanLibraryMutation.mutate()
  }
  
  const toggleExpanded = (id: string) => {
    const newExpanded = new Set(expandedItems)
    if (newExpanded.has(id)) {
      newExpanded.delete(id)
    } else {
      newExpanded.add(id)
    }
    setExpandedItems(newExpanded)
  }
  
  const libraryTree: TreeItem[] = [
    {
      id: 'library',
      label: 'Library',
      icon: <HardDrive className="h-4 w-4" />,
      children: [
        { id: 'all-photos', label: 'All Photos', icon: <Image className="h-4 w-4" />, count: 0 },
        { id: 'rated', label: 'Rated', icon: <Star className="h-4 w-4" />, count: 0 },
        { id: 'discarded', label: 'Discarded', icon: <Trash2 className="h-4 w-4" />, count: 0 },
      ],
    },
    {
      id: 'folders',
      label: 'Folders',
      icon: <Folder className="h-4 w-4" />,
      children: foldersData?.folders?.map((folder: any) => ({
        id: `folder-${folder.id}`,
        label: folder.name || folder.path.split('/').pop() || folder.path,
        icon: <Folder className="h-4 w-4" />,
        count: folder.photo_count,
        type: 'folder',
      })) || [],
    },
  ]
  
  // Derive whether a tree item is currently the "active" filter target.
  // Folder rows are selected when the filter store's folderId matches; the
  // library "All Photos" virtual node is selected when no folder/heap filter
  // is set.
  const isItemActive = (id: string): boolean => {
    if (id.startsWith('folder-')) {
      return filterFolderId === id.slice('folder-'.length)
    }
    if (id === 'all-photos') {
      return filterFolderId === null && selectedItem === 'all-photos'
    }
    return selectedItem === id
  }

  // Which tree items accept photo drops, and what each does on drop.
  const isDropTarget = (id: string): boolean => {
    return id === 'discarded' || id.startsWith('folder-')
  }

  const handleDrop = (id: string, ids: string[]) => {
    if (id === 'discarded') {
      discardDropMutation.mutate(ids)
      return
    }
    if (id.startsWith('folder-')) {
      const targetId = id.slice('folder-'.length)
      moveDropMutation.mutate({ targetId, photoIds: ids })
    }
  }

  const renderTreeItem = (item: TreeItem, depth: number = 0) => {
    const hasChildren = item.children && item.children.length > 0
    const isExpanded = expandedItems.has(item.id)
    const isSelected = isItemActive(item.id)
    const acceptsDrop = isDropTarget(item.id)
    const isDropHover = dropTargetId === item.id

    return (
      <div key={item.id}>
        <div
          className={clsx(
            'group flex cursor-pointer items-center gap-1 rounded px-2 py-1 text-sm',
            isSelected ? 'bg-primary/20 text-primary' : 'text-text hover:bg-surface-2',
            isDropHover && (item.id === 'discarded'
              ? 'ring-2 ring-reject bg-reject/10'
              : 'ring-2 ring-primary bg-primary/10'),
            depth > 0 && 'text-[13px]'
          )}
          style={{ paddingLeft: `${8 + depth * 16}px` }}
          onClick={() => {
            setSelectedItem(item.id)
            if (hasChildren) {
              toggleExpanded(item.id)
            } else {
              applyLibraryNode(item.id)
            }
          }}
          onDragOver={acceptsDrop ? (e) => {
            if (e.dataTransfer.types.includes(PHOTO_DRAG_MIME)) {
              e.preventDefault()
              e.dataTransfer.dropEffect = item.id === 'discarded' ? 'move' : 'move'
              if (dropTargetId !== item.id) setDropTargetId(item.id)
            }
          } : undefined}
          onDragLeave={acceptsDrop ? (e) => {
            if (!e.currentTarget.contains(e.relatedTarget as Node)) {
              if (dropTargetId === item.id) setDropTargetId(null)
            }
          } : undefined}
          onDrop={acceptsDrop ? (e) => {
            e.preventDefault()
            setDropTargetId(null)
            const ids = readDragIds(e)
            if (ids) handleDrop(item.id, ids)
          } : undefined}
        >
          {/* Expand/Collapse Icon */}
          {hasChildren ? (
            <button
              onClick={(e) => {
                e.stopPropagation()
                toggleExpanded(item.id)
              }}
              className="rounded p-0.5 hover:bg-surface-offset"
            >
              {isExpanded ? (
                <ChevronDown className="h-3 w-3" />
              ) : (
                <ChevronRight className="h-3 w-3" />
              )}
            </button>
          ) : (
            <div className="w-4" />
          )}
          
          {/* Item Icon */}
          {item.icon && (
            <span className={clsx('flex-shrink-0', isSelected ? 'text-primary' : 'text-text-muted')}>
              {item.icon}
            </span>
          )}
          
          {/* Label */}
          <span className="flex-1 truncate">{item.label}</span>
          
          {/* Count Badge */}
          {item.count !== undefined && item.count > 0 && (
            <span className="rounded bg-surface-offset px-1.5 py-0.5 text-xs text-text-muted">
              {item.count}
            </span>
          )}
          
          {/* Actions (shown on hover) */}
          {(item.id === 'folders' || item.id === 'heaps') && (
            <button
              onClick={(e) => {
                e.stopPropagation()
                // Handle add folder/heap
              }}
              className="invisible rounded p-0.5 text-text-muted hover:bg-surface-offset hover:text-text group-hover:visible"
            >
              <Plus className="h-3 w-3" />
            </button>
          )}
        </div>
        
        {/* Render Children */}
        {hasChildren && isExpanded && (
          <div>
            {item.children!.map((child) => renderTreeItem(child, depth + 1))}
          </div>
        )}
      </div>
    )
  }
  
  return (
    <div className="flex h-full flex-col bg-surface">
      {/* Sidebar Header */}
      <div className="flex items-center justify-between border-b border-border px-3 py-2">
        <h2 className="text-sm font-semibold text-text">Library</h2>
        <button className="rounded p-1 text-text-muted hover:bg-surface-2 hover:text-text">
          <MoreHorizontal className="h-4 w-4" />
        </button>
      </div>
      
      {/* Tree View */}
      <div className="flex-1 overflow-y-auto py-2">
        {libraryTree.map((item) => renderTreeItem(item))}
        <HeapsPanel />
      </div>
      
      {/* Bottom Actions */}
      <div className="border-t border-border p-3 space-y-2">
        <button 
          onClick={() => setShowAddFolderDialog(true)}
          className="flex w-full items-center gap-2 rounded bg-surface-2 px-3 py-2 text-sm text-text hover:bg-surface-offset"
        >
          <Plus className="h-4 w-4" />
          Add Source Folder
        </button>
        {foldersData?.folders?.length > 0 && (
          <button 
            onClick={handleScanAll}
            disabled={isScanning}
            className="flex w-full items-center gap-2 rounded bg-surface-2 px-3 py-2 text-sm text-text hover:bg-surface-offset disabled:opacity-50"
          >
            <RefreshCw className={clsx("h-4 w-4", isScanning && "animate-spin")} />
            {isScanning ? 'Scanning...' : 'Scan All Folders'}
          </button>
        )}
      </div>
      
      {/* Add Source Folder Dialog */}
      <AddSourceFolderDialog
        isOpen={showAddFolderDialog}
        onClose={() => setShowAddFolderDialog(false)}
        onAdd={handleAddFolder}
      />
    </div>
  )
}