/**
 * useWhiteboard - Vue 组合式函数
 *
 * 整合三层架构：
 * - BoardModel（数据模型）
 * - BoardRenderer（渲染层）
 * - BoardInteractionManager（交互系统）
 */

import { ref, onUnmounted, computed, watch, type Ref } from 'vue'
import { BoardModel } from './core/BoardModel'
import { BoardHistoryManager } from './core/BoardHistoryManager'
import { BoardRenderer } from './renderer/BoardRenderer'
import { BoardInteractionManager } from './interaction/BoardInteractionManager'
import type {
  ElementType, ToolType, Viewport, Point,
  BoardElement, SerializedBoard, ElementStyle,
  Connection, BoardPage, STICKY_NOTE_COLORS,
} from './core/types'

import { STICKY_NOTE_COLORS as STICKY_COLORS } from './core/types'

interface UseWhiteboardOptions {
  initialData?: SerializedBoard
  width?: number
  height?: number
  /** 双击元素回调（用于启动文本编辑） */
  onElementDblClick?: (elementId: string | null) => void
  /** 橡皮擦悬停回调 */
  onEraserHover?: (element: { x: number; y: number; width: number; height: number } | null) => void
}

export function useWhiteboard(options: UseWhiteboardOptions = {}) {
  const { onElementDblClick, onEraserHover } = options
  // 状态
  const board = ref<BoardModel>(new BoardModel())
  const renderer = ref<BoardRenderer | null>(null)
  const interaction = ref<BoardInteractionManager | null>(null)
  const canvasRef = ref<HTMLCanvasElement | null>(null)
  const currentTool = ref<ToolType>('select')
  const currentZoom = ref(1)

  // 选中元素的 ID（响应式，供 Vue 模板直接使用）
  const selectedIds = ref<string[]>([])

  // 历史管理器
  const historyManager = new BoardHistoryManager({ maxHistory: 50 })
  const historyVersion = ref(0)

  // 内部状态
  let renderLoopRunning = false
  let boardChangeListener: (() => void) | null = null

  /**
   * 绑定数据变更监听器
   */
  function bindBoardChangeListener(): void {
    if (boardChangeListener) boardChangeListener()
    boardChangeListener = board.value.onChange(() => {
      renderer.value?.forceRedraw()
    })
  }

  /**
   * 初始化 Canvas
   */
  function initCanvas(canvas: HTMLCanvasElement, initialData?: SerializedBoard | null): boolean {
    canvasRef.value = canvas
    const parent = canvas.parentElement
    const width = options.width || parent?.clientWidth || canvas.clientWidth || 800
    const height = options.height || parent?.clientHeight || canvas.clientHeight || 600

    // 创建渲染器
    renderer.value = new BoardRenderer(canvas, { width, height })

    if (initialData) {
      board.value = BoardModel.deserialize(initialData)
      const vp = (initialData as any).viewport
      if (vp) {
        renderer.value.setViewport(vp)
        currentZoom.value = vp.zoom ?? 1
      }
    }

    // 创建交互管理器
    interaction.value = new BoardInteractionManager(canvas, renderer.value, board.value)

    // 监听工具变更
    interaction.value.on('tool:change', (e) => {
      if (e.tool) currentTool.value = e.tool
    })

    // 监听双击（用于编辑文本）— 转发给 Vue 组件
    interaction.value.on('element:dblclick', (e) => {
      onElementDblClick?.(e.elementId || null)
    })

    // 监听选择变更 — 同步到响应式 selectedIds，使 Vue 模板能够感知变化
    interaction.value.on('selection:change', (e) => {
      selectedIds.value = e.selectedIds ?? []
    })

    // 监听滚轮缩放 — 同步到响应式 currentZoom，使 Vue 工具栏百分比实时更新
    interaction.value.on('zoom', (e) => {
      currentZoom.value = e.viewport.zoom
    })

    // 监听橡皮擦悬停 — 同步到响应式 eraserHoverElement，使 Vue 模板能够感知变化
    interaction.value.on('eraser:hover', (e) => {
      onEraserHover?.(e.eraserHoverElement ?? null)
    })

    // 绑定数据变更监听
    bindBoardChangeListener()

    // 初始化历史
    historyManager.init(board.value.serialize())

    // 初始渲染
    requestRender()

    // 启动渲染循环
    startRenderLoop()

    return !initialData
  }

  /**
   * 持续渲染循环
   *
   * 每帧检查 renderer 脏标记，只有脏时才绘制。
   * 比事件驱动更可靠——不会遗漏任何数据变更。
   * 空闲时几乎零开销（只做一次布尔判断）。
   */
  function startRenderLoop(): void {
    if (renderLoopRunning) return
    renderLoopRunning = true

    function loop() {
      if (!renderLoopRunning) return
      if (renderer.value) {
        try {
          renderer.value.render(board.value)
        } catch (e) {
          console.error('[Whiteboard] Render error:', e)
        }
      }
      requestAnimationFrame(loop)
    }
    requestAnimationFrame(loop)
  }

  /**
   * 请求渲染（兼容旧调用点）
   */
  function requestRender(): void {
    renderer.value?.forceRedraw()
  }

  // ===== 元素操作 =====

  /** 添加元素 */
  function addElement(type: ElementType, options: Partial<BoardElement> = {}): BoardElement {
    const el = board.value.addElement(type, options)
    saveHistory(`add-${type}`)
    return el
  }

  /** 删除选中元素 */
  function deleteSelected(): void {
    const ids = interaction.value?.getSelectedIds() || []
    if (ids.length === 0) return
    board.value.removeElements(ids)
    interaction.value?.clearSelection()
    saveHistory('delete')
  }

  /** 更新元素 */
  function updateElement(id: string, updates: Partial<BoardElement>): BoardElement | undefined {
    const el = board.value.updateElement(id, updates)
    saveHistory('update')
    return el
  }

  /** 更新元素样式 */
  function updateElementStyle(id: string, style: Partial<ElementStyle>): void {
    board.value.updateElementStyle(id, style)
    saveHistory('style-update')
  }

  /** 移动元素到最前 */
  function bringToFront(id: string): void {
    board.value.bringToFront(id)
    saveHistory('bring-to-front')
  }

  /** 移动元素到最后 */
  function sendToBack(id: string): void {
    board.value.sendToBack(id)
    saveHistory('send-to-back')
  }

  /** 复制元素 */
  function duplicateElement(id: string): string | undefined {
    const copy = board.value.duplicateElement(id)
    if (copy) {
      saveHistory('duplicate')
      return copy.id
    }
  }

  /** 更新元素位置 */
  function updateElementPosition(id: string, x: number, y: number): void {
    board.value.updateElementPosition(id, x, y)
    saveHistory('move')
  }

  /** 更新元素尺寸 */
  function updateElementSize(id: string, width: number, height: number): void {
    board.value.updateElementSize(id, width, height)
    saveHistory('resize')
  }

  // ===== 连接操作 =====

  /** 添加连接 */
  function addConnection(sourceId: string, targetId: string, options: Partial<Connection> = {}): Connection | undefined {
    const conn = board.value.addConnection(sourceId, targetId, options)
    saveHistory('add-connection')
    return conn
  }

  /** 删除连接 */
  function removeConnection(id: string): void {
    board.value.removeConnection(id)
    saveHistory('remove-connection')
  }

  // ===== 页面操作 =====

  /** 获取页面列表 */
  const pages = computed(() => board.value.pages)

  /** 当前页面ID */
  const activePageId = computed(() => board.value.activePageId)

  /** 添加页面 */
  function addPage(name?: string): BoardPage {
    const page = board.value.addPage(name)
    saveHistory('add-page')
    return page
  }

  /** 切换页面 */
  function setActivePage(pageId: string): void {
    board.value.setActivePage(pageId)
    interaction.value?.clearSelection()
    saveHistory('switch-page')
    requestRender()
  }

  /** 删除页面 */
  function removePage(pageId: string): void {
    board.value.removePage(pageId)
    saveHistory('remove-page')
  }

  /** 重命名页面 */
  function renamePage(pageId: string, name: string): void {
    board.value.renamePage(pageId, name)
  }

  // ===== 视口 =====

  function zoomIn(): void {
    const vp = renderer.value?.getViewport()
    if (!vp) return
    const newZoom = Math.min(5, vp.zoom + 0.2)
    const centerX = (renderer.value as any).config.width / 2
    const centerY = (renderer.value as any).config.height / 2
    const worldCenter = renderer.value!.screenToWorld({ x: centerX, y: centerY })
    renderer.value!.setViewport({
      zoom: newZoom,
      panX: centerX - worldCenter.x * newZoom,
      panY: centerY - worldCenter.y * newZoom,
    })
    currentZoom.value = newZoom
    requestRender()
  }

  function zoomOut(): void {
    const vp = renderer.value?.getViewport()
    if (!vp) return
    const newZoom = Math.max(0.1, vp.zoom - 0.2)
    const centerX = (renderer.value as any).config.width / 2
    const centerY = (renderer.value as any).config.height / 2
    const worldCenter = renderer.value!.screenToWorld({ x: centerX, y: centerY })
    renderer.value!.setViewport({
      zoom: newZoom,
      panX: centerX - worldCenter.x * newZoom,
      panY: centerY - worldCenter.y * newZoom,
    })
    currentZoom.value = newZoom
    requestRender()
  }

  function resetZoom(): void {
    renderer.value?.setViewport({ zoom: 1, panX: 0, panY: 0 })
    currentZoom.value = 1
    requestRender()
  }

  function fitView(): void {
    const bounds = board.value.getElementBounds(
      board.value.activePageElements.map(el => el.id)
    )
    if (!bounds || !renderer.value) return

    const canvasW = (renderer.value as any).config.width
    const canvasH = (renderer.value as any).config.height
    const padding = 60

    const zoom = Math.min(
      (canvasW - padding * 2) / bounds.width,
      (canvasH - padding * 2) / bounds.height,
      2
    )

    const panX = canvasW / 2 - (bounds.x + bounds.width / 2) * zoom
    const panY = canvasH / 2 - (bounds.y + bounds.height / 2) * zoom

    renderer.value.setViewport({ zoom, panX, panY })
    currentZoom.value = zoom
    requestRender()
  }

  // ===== 工具 =====

  function setTool(tool: ToolType): void {
    currentTool.value = tool
    interaction.value?.setTool(tool)
  }

  // ===== 选择 =====

  function getSelectedIds(): string[] {
    return interaction.value?.getSelectedIds() || []
  }

  function setSelectedIds(ids: string[]): void {
    interaction.value?.setSelectedIds(ids)
    selectedIds.value = ids
  }

  function clearSelection(): void {
    interaction.value?.clearSelection()
    selectedIds.value = []
  }

  // ===== 数据导入导出 =====

  function exportData(): SerializedBoard & { viewport: Viewport } {
    return {
      ...board.value.serialize(),
      viewport: renderer.value.getViewport(),
    }
  }

  function importData(data: SerializedBoard): void {
    board.value = BoardModel.deserialize(data)
    const vp = (data as any).viewport
    if (vp) {
      renderer.value?.setViewport(vp)
      currentZoom.value = vp.zoom ?? 1
    }
    interaction.value?.setBoard(board.value)
    bindBoardChangeListener()
    requestRender()
  }

  // ===== 历史管理 =====

  function saveHistory(action?: string): void {
    historyManager.push(board.value.serialize(), action)
    historyVersion.value++
  }

  function clearHistory(): void {
    historyManager.clear()
    historyVersion.value++
  }

  const canUndo = computed(() => {
    historyVersion.value
    return historyManager.canUndo
  })

  const canRedo = computed(() => {
    historyVersion.value
    return historyManager.canRedo
  })

  function undo(): boolean {
    const item = historyManager.undo()
    if (item) {
      importData(item.data)
      historyVersion.value++
      return true
    }
    return false
  }

  function redo(): boolean {
    const item = historyManager.redo()
    if (item) {
      importData(item.data)
      historyVersion.value++
      return true
    }
    return false
  }

  // ===== Resize =====

  function resize(): void {
    if (!canvasRef.value || !renderer.value) return
    const parent = canvasRef.value.parentElement
    if (!parent) return
    renderer.value.resize(parent.clientWidth, parent.clientHeight)
    requestRender()
  }

  // ===== Board ref 变更保障 =====

  /**
   * 当 board ref 被整体替换时（如 handlePgUpdate / importData / undo / redo），
   * onChange 监听器不会对"替换"本身触发，需要 watch 保障重绘。
   */
  watch(board, () => {
    requestRender()
  })

  // ===== 销毁 =====

  onUnmounted(() => {
    renderLoopRunning = false
    if (interaction.value) {
      interaction.value.unbindEvents()
    }
    if (boardChangeListener) {
      boardChangeListener()
    }
  })

  return {
    board,
    renderer,
    interaction,
    canvasRef,
    currentTool,
    // 响应式选中 ID（模板直接使用）
    selectedIds,
    initCanvas,
    bindBoardChangeListener,
    // 元素操作
    addElement,
    deleteSelected,
    updateElement,
    updateElementStyle,
    updateElementPosition,
    updateElementSize,
    bringToFront,
    sendToBack,
    duplicateElement,
    // 连接
    addConnection,
    removeConnection,
    // 页面
    pages,
    activePageId,
    addPage,
    setActivePage,
    removePage,
    renamePage,
    // 视口
    zoomIn,
    zoomOut,
    resetZoom,
    fitView,
    currentZoom,
    // 工具
    setTool,
    // 选择
    getSelectedIds,
    setSelectedIds,
    clearSelection,
    // 数据
    exportData,
    importData,
    // 历史
    canUndo,
    canRedo,
    undo,
    redo,
    saveHistory,
    clearHistory,
    // 其他
    resize,
    requestRender,
    cancelDrawing: () => interaction.value?.cancelDrawing(),
    // 便利贴颜色
    stickyNoteColors: STICKY_COLORS,
  }
}

export default useWhiteboard
