import type { Ref } from 'vue'
import { ref } from 'vue'
import type { DropdownInstance, TreeV2Instance } from 'element-plus'

interface NodeBase<T> { id: string; label: string; children?: T[] }
type NodeType<T> = T & NodeBase<T>
type LocateResult<T> = { node: NodeType<T>; parent: NodeType<T> | null; container: NodeType<T>[]; index: number } | null

interface MenuItem { key: string; text: string; disabled?: boolean }

interface ContextMenuConfig<T> {
  dataRef: Ref<NodeType<T>[]>;
  treeRef: Ref<TreeV2Instance | undefined>;
  expandedKeysRef: Ref<string[]>;
  locate: (id: string) => LocateResult<T>;
  startEdit: (node: NodeType<T>) => void;
}

interface ContextMenuContext<T> {
  createNode: (prefix: string) => NodeType<T>;
  setData: (next: NodeType<T>[]) => void;
  expandNode: (id: string) => void;
  setCurrentKey: (id: string) => void;
  locate: (id: string) => LocateResult<T>;
  startEdit: (node: NodeType<T>) => void;
  dataRef: Ref<NodeType<T>[]>;
}

interface LevelConfig {
  depth: number
  addKey?: string
  addText?: string
  allowDelete?: boolean
}

interface HierarchyConfig {
  rootKey: string
  rootText: string
  levels: LevelConfig[]
}

interface ContextMenuHandler<T> {
  getMenuItems: (node: NodeType<T> | null, ctx: ContextMenuContext<T>) => MenuItem[];
  execute: (cmd: string, node: NodeType<T> | null, ctx: ContextMenuContext<T>) => Promise<void> | void;
}

/**
 * 获取节点深度
 */
const getDepth = <T>(node: NodeType<T>, ctx: ContextMenuContext<T>): number => {
  const target = ctx.locate(node.id)
  if (!target) return -1
  let depth = 0
  let p = target.parent
  while (p) {
    depth += 1
    const pt = ctx.locate(p.id)
    p = pt?.parent ?? null
  }
  return depth
}

/**
 * 层级化上下文菜单处理器
 */
class HierarchyContextMenuHandler<T> implements ContextMenuHandler<T> {
  constructor(private config: HierarchyConfig) {}

  getMenuItems = (node: NodeType<T> | null, ctx: ContextMenuContext<T>): MenuItem[] => {
    // 空白区域右键 - 添加根节点
    if (!node) {
      return [{ key: this.config.rootKey, text: this.config.rootText }]
    }
    
    const depth = getDepth(node, ctx)
    const levelConfig = this.config.levels.find(l => l.depth === depth)
    
    if (!levelConfig) {
      // 未配置的层级，只显示删除
      return [{ key: 'delete', text: '删除' }]
    }
    
    const items: MenuItem[] = []
    
    // 添加子级菜单项
    if (levelConfig.addKey && levelConfig.addText) {
      items.push({ key: levelConfig.addKey, text: levelConfig.addText })
    }
    
    // 删除菜单项
    if (levelConfig.allowDelete !== false) {
      items.push({ key: 'delete', text: '删除' })
    }
    
    return items
  }

  execute = async (cmd: string, node: NodeType<T> | null, ctx: ContextMenuContext<T>) => {
    // 添加根节点
    if (!node && cmd === this.config.rootKey) {
      const next = ctx.createNode('root')
      next.label = this.config.rootText.replace('添加', '')
      ctx.setData([...ctx.dataRef.value, next])
      return
    }
    
    if (!node) return
    
    // 删除节点
    if (cmd === 'delete') {
      const target = ctx.locate(node.id)
      if (!target) return
      target.container.splice(target.index, 1)
      ctx.setData([...ctx.dataRef.value])
      return
    }
    
    // 查找匹配的层级配置
    const depth = getDepth(node, ctx)
    const levelConfig = this.config.levels.find(l => l.depth === depth && l.addKey === cmd)
    
    if (levelConfig) {
      const target = ctx.locate(node.id)
      if (!target) return
      
      const next = ctx.createNode(node.id)
      next.label = levelConfig.addText?.replace('添加', '') || '新目录'
      
      target.node.children = target.node.children || []
      target.node.children.push(next)
      ctx.setData([...ctx.dataRef.value])
      ctx.expandNode(target.node.id)
      ctx.setCurrentKey(next.id)
    }
  }
}

/**
 * 默认上下文菜单处理器
 */
class DefaultContextMenuHandler<T> implements ContextMenuHandler<T> {
  getMenuItems = (node: NodeType<T> | null, _ctx: ContextMenuContext<T>): MenuItem[] => {
    if (!node) return [{ key: 'add-root', text: '添加根目录' }]
    return [
      { key: 'add-sibling', text: '添加目录' },
      { key: 'add-child', text: '添加子目录' },
      { key: 'rename', text: '重命名' },
      { key: 'delete', text: '删除' },
    ]
  }

  execute = async (cmd: string, node: NodeType<T> | null, ctx: ContextMenuContext<T>) => {
    if (!node && cmd === 'add-root') {
      ctx.setData([...ctx.dataRef.value, ctx.createNode('node')])
      return
    }
    if (!node) return
    if (cmd === 'add-sibling') {
      const target = ctx.locate(node.id)
      if (!target) return
      const prefix = target.parent ? target.parent.id : 'node'
      target.container.push(ctx.createNode(prefix))
      ctx.setData([...ctx.dataRef.value])
      return
    }
    if (cmd === 'add-child') {
      const target = ctx.locate(node.id)
      if (!target) return
      target.node.children = target.node.children || []
      target.node.children.push(ctx.createNode(target.node.id))
      ctx.setData([...ctx.dataRef.value])
      ctx.expandNode(target.node.id)
      ctx.setCurrentKey(target.node.id)
      return
    }
    if (cmd === 'rename') { ctx.startEdit(node); return }
    if (cmd === 'delete') {
      const target = ctx.locate(node.id)
      if (!target) return
      target.container.splice(target.index, 1)
      ctx.setData([...ctx.dataRef.value])
    }
  }
}

class DbTreeContextMenu<T> {
  dropdownRef = ref<DropdownInstance>()
  position = ref({ top: 0, left: 0, bottom: 0, right: 0 } as DOMRect)
  triggerRef = ref({ getBoundingClientRect: () => this.position.value })
  currentNode = ref<NodeType<T> | null>(null)

  private config: ContextMenuConfig<T>
  private handler: ContextMenuHandler<T>

  constructor(config: ContextMenuConfig<T>, handler?: ContextMenuHandler<T>) {
    this.config = config
    this.handler = handler ?? new DefaultContextMenuHandler<T>()
  }

  private createNode = (prefix: string): NodeType<T> => {
    const suffix = Math.random().toString(36).slice(2, 8)
    const id = `${prefix}-${suffix}`
    return { id, label: '新目录' } as NodeType<T>
  }

  private setData = (next: NodeType<T>[]) => { this.config.dataRef.value = next }
  private expandNode = (id: string) => {
    const keys = Array.from(new Set([...this.config.expandedKeysRef.value, id]))
    this.config.expandedKeysRef.value = keys
    this.config.treeRef.value?.setExpandedKeys(keys)
  }
  private setCurrentKey = (id: string) => { this.config.treeRef.value?.setCurrentKey?.(id) }
  private ctx = (): ContextMenuContext<T> => ({
    createNode: this.createNode,
    setData: this.setData,
    expandNode: this.expandNode,
    setCurrentKey: this.setCurrentKey,
    locate: this.config.locate,
    startEdit: this.config.startEdit,
    dataRef: this.config.dataRef,
  })

  getMenuItems = (): MenuItem[] => this.handler.getMenuItems(this.currentNode.value, this.ctx())

  openContextMenu = (event: MouseEvent, nodeData: NodeType<T>) => {
    const { clientX, clientY } = event
    this.position.value = DOMRect.fromRect({ x: clientX, y: clientY })
    event.preventDefault()
    this.currentNode.value = nodeData
    this.dropdownRef.value?.handleOpen()
  }

  openBlankContextMenu = (event: MouseEvent) => {
    const { clientX, clientY } = event
    this.position.value = DOMRect.fromRect({ x: clientX, y: clientY })
    event.preventDefault()
    this.currentNode.value = null
    this.dropdownRef.value?.handleOpen()
  }

  closeContextMenu = () => { this.dropdownRef.value?.handleClose() }

  onCommand = async (cmd: string) => { await this.handler.execute(cmd, this.currentNode.value, this.ctx()) }

  onGlobalCommand = (cmd: string) => { void this.handler.execute(cmd, this.currentNode.value, this.ctx()) }
}

/**
 * 创建层级化的上下文菜单处理器
 * @param config 层级配置
 * @returns ContextMenuHandler
 */
const createHierarchyContextMenuHandler = <T>(config: HierarchyConfig): ContextMenuHandler<T> => {
  return new HierarchyContextMenuHandler<T>(config)
}

const createContextMenu = <T>(config: ContextMenuConfig<T>, handler?: ContextMenuHandler<T> | HierarchyConfig) => {
  // 如果传入的是 HierarchyConfig，自动创建 HierarchyContextMenuHandler
  if (handler && 'rootKey' in handler && 'rootText' in handler && 'levels' in handler) {
    return new DbTreeContextMenu<T>(config, createHierarchyContextMenuHandler<T>(handler))
  }
  return new DbTreeContextMenu<T>(config, handler as ContextMenuHandler<T> | undefined)
}

export { DbTreeContextMenu, HierarchyContextMenuHandler, createHierarchyContextMenuHandler }
export type { ContextMenuConfig, ContextMenuHandler, MenuItem, NodeType, LocateResult, HierarchyConfig, LevelConfig }

export const useContextMenu = <T>(config: ContextMenuConfig<T>, handler?: ContextMenuHandler<T> | HierarchyConfig) => createContextMenu<T>(config, handler)
