'use client'

import React, { useMemo, useState } from 'react'
import {
  ChevronRight,
  ChevronDown,
  Folder,
  FolderOpen,
  Check,
  Search,
  StickyNote,
} from 'lucide-react'
import { motion, AnimatePresence } from 'motion/react'

export type NotebookPickerItem = {
  id: string
  name: string
  icon?: string | null
  parentId?: string | null
  trashedAt?: Date | string | null
}

const PANEL_WIDTH = 280
const PANEL_HEIGHT = 350
const VIEWPORT_PADDING = 8

export function getNotebookPickerPosition(
  rect: DOMRect,
  options?: { preferDropUp?: boolean; align?: 'start' | 'end'; panelWidth?: number; panelHeight?: number },
): React.CSSProperties {
  const panelWidth = options?.panelWidth ?? PANEL_WIDTH
  const panelHeight = options?.panelHeight ?? PANEL_HEIGHT
  const align = options?.align ?? 'start'
  const viewportWidth = window.innerWidth
  const viewportHeight = window.innerHeight

  let left = align === 'end' ? rect.right - panelWidth : rect.left
  left = Math.max(VIEWPORT_PADDING, Math.min(left, viewportWidth - panelWidth - VIEWPORT_PADDING))

  const spaceBelow = viewportHeight - rect.bottom - VIEWPORT_PADDING
  const spaceAbove = rect.top - VIEWPORT_PADDING
  const preferDropUp = options?.preferDropUp ?? false
  const openUp = preferDropUp || (spaceBelow < panelHeight && spaceAbove > spaceBelow)

  if (openUp) {
    const bottom = viewportHeight - rect.top + VIEWPORT_PADDING
    return {
      position: 'fixed',
      bottom: Math.max(VIEWPORT_PADDING, bottom),
      left,
      width: panelWidth,
      maxHeight: Math.min(panelHeight, rect.top - VIEWPORT_PADDING * 2),
      zIndex: 9999,
    }
  }

  const top = rect.bottom + VIEWPORT_PADDING
  return {
    position: 'fixed',
    top: Math.min(top, viewportHeight - VIEWPORT_PADDING),
    left,
    width: panelWidth,
    maxHeight: Math.min(panelHeight, viewportHeight - top - VIEWPORT_PADDING),
    zIndex: 9999,
  }
}

type NotebookHierarchyPanelProps = {
  notebooks: NotebookPickerItem[]
  selectedId?: string | null
  onSelect: (id: string) => void
  onClose: () => void
  searchPlaceholder?: string
  footerLabel?: string
  closeLabel?: string
  showGeneralNotes?: boolean
  generalNotesLabel?: string
  onSelectGeneralNotes?: () => void
  className?: string
  style?: React.CSSProperties
}

export function NotebookHierarchyPanel({
  notebooks,
  selectedId = null,
  onSelect,
  onClose,
  searchPlaceholder = 'Filter notebooks…',
  footerLabel,
  closeLabel = 'Close',
  showGeneralNotes = false,
  generalNotesLabel = 'General Notes',
  onSelectGeneralNotes,
  className = '',
  style,
}: NotebookHierarchyPanelProps) {
  const [searchQuery, setSearchQuery] = useState('')
  const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set())

  const activeNotebooks = useMemo(
    () => notebooks.filter((nb) => !nb.trashedAt),
    [notebooks],
  )

  const toggleExpand = (e: React.MouseEvent, id: string) => {
    e.stopPropagation()
    const next = new Set(expandedIds)
    if (next.has(id)) next.delete(id)
    else next.add(id)
    setExpandedIds(next)
  }

  const renderTree = (parentId: string | null | undefined, level = 0): React.ReactNode => {
    const children = activeNotebooks.filter((nb) => (nb.parentId ?? null) === (parentId ?? null))
    if (children.length === 0) return null

    return (
      <div className={level > 0 ? 'ms-4 border-s border-border/40 ps-2' : ''}>
        {children.map((notebook) => {
          const isExpanded = expandedIds.has(notebook.id) || searchQuery.length > 0
          const hasChildren = activeNotebooks.some((nb) => nb.parentId === notebook.id)
          const isSelected = selectedId === notebook.id

          if (searchQuery && !notebook.name.toLowerCase().includes(searchQuery.toLowerCase())) {
            const hasMatchingChild = (id: string): boolean => {
              const kids = activeNotebooks.filter((nb) => nb.parentId === id)
              return kids.some(
                (nb) =>
                  nb.name.toLowerCase().includes(searchQuery.toLowerCase()) || hasMatchingChild(nb.id),
              )
            }
            if (!hasMatchingChild(notebook.id)) return null
          }

          return (
            <div key={notebook.id} className="select-none">
              <div
                onClick={() => {
                  onSelect(notebook.id)
                  if (!searchQuery) onClose()
                }}
                className={`flex items-center gap-2.5 px-2 py-1.5 rounded-lg cursor-pointer transition-all group
                  ${isSelected ? 'bg-brand-accent/15 text-brand-accent font-bold dark:bg-brand-accent/20' : 'hover:bg-muted dark:hover:bg-white/5 text-ink'}`}
              >
                <div className="w-4 flex items-center justify-center">
                  {hasChildren ? (
                    <button
                      type="button"
                      onClick={(e) => toggleExpand(e, notebook.id)}
                      className="p-1 hover:bg-black/5 dark:hover:bg-white/5 rounded transition-colors"
                    >
                      {isExpanded ? <ChevronDown size={12} /> : <ChevronRight size={12} />}
                    </button>
                  ) : null}
                </div>

                <div
                  className={`p-1 rounded ${isSelected ? 'bg-brand-accent/25 dark:bg-brand-accent/30' : 'bg-muted/50 dark:bg-white/5 group-hover:bg-white/40'}`}
                >
                  {isExpanded && hasChildren ? <FolderOpen size={13} /> : <Folder size={13} />}
                </div>

                <span className="text-[13px] truncate flex-1">{notebook.name}</span>

                {isSelected && <Check size={14} className="opacity-60 shrink-0" />}
              </div>

              <AnimatePresence>
                {isExpanded && (
                  <motion.div
                    initial={{ height: 0, opacity: 0 }}
                    animate={{ height: 'auto', opacity: 1 }}
                    exit={{ height: 0, opacity: 0 }}
                    className="overflow-hidden"
                  >
                    {renderTree(notebook.id, level + 1)}
                  </motion.div>
                )}
              </AnimatePresence>
            </div>
          )
        })}
      </div>
    )
  }

  return (
    <motion.div
      initial={{ opacity: 0, y: 8, scale: 0.98 }}
      animate={{ opacity: 1, y: 0, scale: 1 }}
      exit={{ opacity: 0, y: 8, scale: 0.98 }}
      transition={{ duration: 0.15 }}
      style={style}
      className={`bg-card border border-border shadow-2xl rounded-2xl overflow-hidden flex flex-col min-w-0 ${className}`}
      onClick={(e) => e.stopPropagation()}
    >
      <div className="p-3 border-b border-border/40 bg-card/50 dark:bg-white/5 shrink-0">
        <div className="relative">
          <Search size={14} className="absolute start-3 top-1/2 -translate-y-1/2 text-concrete" />
          <input
            autoFocus
            type="text"
            value={searchQuery}
            onChange={(e) => setSearchQuery(e.target.value)}
            placeholder={searchPlaceholder}
            className="w-full bg-card border border-border rounded-lg ps-9 pe-4 py-2 text-xs outline-none focus:border-brand-accent transition-colors"
          />
        </div>
      </div>

      <div className="min-h-0 flex-1 overflow-y-auto custom-scrollbar p-2">
        {showGeneralNotes && onSelectGeneralNotes && (
          <button
            type="button"
            onClick={() => {
              onSelectGeneralNotes()
              onClose()
            }}
            className="w-full flex items-center gap-2.5 px-2 py-1.5 rounded-lg cursor-pointer transition-all hover:bg-muted dark:hover:bg-white/5 text-ink mb-1"
          >
            <div className="p-1 rounded bg-muted/50 dark:bg-white/5">
              <StickyNote size={13} />
            </div>
            <span className="text-[13px] truncate flex-1 text-start">{generalNotesLabel}</span>
          </button>
        )}
        {renderTree(null)}
      </div>

      <div className="p-2 border-t border-border/40 bg-card/30 dark:bg-white/5 flex justify-between items-center px-4 shrink-0">
        {footerLabel ? (
          <span className="text-[9px] font-bold text-muted-foreground uppercase tracking-widest">{footerLabel}</span>
        ) : (
          <span />
        )}
        <button type="button" onClick={onClose} className="text-[10px] font-bold text-brand-accent hover:underline">
          {closeLabel}
        </button>
      </div>
    </motion.div>
  )
}
