import { createContext, useContext, useMemo, type RefObject } from 'react'
import { useStoreWithEqualityFn } from 'zustand/traditional'
import type { DominoStore, DominoStoreState } from './domino-store'
import { getElementsBounds } from './math'
import type { DominoCanvasProps } from './domino'

// --- 1. Context Definitions ---

/**
 * Store Context: 核心状态管理器
 */
export const DominoContext = createContext<DominoStore | null>(null)

/**
 * DOM 引用上下文：提供容器节点的稳定引用
 */
export const DominoDOMContext =
  createContext<RefObject<HTMLElement | null> | null>(null)

/**
 * 渲染钩子上下文：提供业务自定义渲染函数
 */
export const DominoRenderHooksContext = createContext<{
  renderElement?: DominoCanvasProps['renderElement']
  renderElementMetadata?: DominoCanvasProps['renderElementMetadata']
}>({})

// --- 2. Store Consumption Hooks ---

export function useDominoStore<T>(
  selector: (state: DominoStoreState) => T,
  equalityFn?: (a: T, b: T) => boolean,
): T {
  const store = useContext(DominoContext)
  if (!store) {
    throw new Error('useDominoStore must be used within a DominoProvider')
  }
  return useStoreWithEqualityFn(store, selector, equalityFn)
}

/**
 * Escape hatch hook to get direct access to the raw Zustand store.
 * Prefer using useDominoInstance or specialized useDomino* hooks.
 */
export function useDominoStoreInstance() {
  const store = useContext(DominoContext)
  if (!store) {
    throw new Error(
      'useDominoStoreInstance must be used within a DominoProvider',
    )
  }
  return store
}

/**
 * Hook to get the current viewport data (x, y, scale)
 */
export function useDominoViewportData() {
  return useDominoStore(state => state.viewport)
}

/**
 * Hook to get all elements in the canvas
 */
export function useDominoElements() {
  return useDominoStore(state => state.elements)
}

/**
 * Hook to get the currently selected element IDs
 */
export function useDominoSelectedIds() {
  return useDominoStore(state => state.selectedIds)
}

/**
 * Hook to get the current interaction mode (select | pan)
 */
export function useDominoMode() {
  return useDominoStore(state => state.mode)
}

/**
 * Hook to get all element UI states (status, loading text, etc.)
 */
export function useDominoElementUIStates() {
  return useDominoStore(state => state.elementUIStates)
}

/**
 * Semantic hook to get the current selection boundary (derived state).
 * Correctly handles single vs multi selection.
 */
export function useDominoSelectionBounds() {
  const selectedIds = useDominoSelectedIds()
  const elements = useDominoElements()
  const [placeholders] = useDominoStore(state => [state.placeholders])

  return useMemo(() => {
    if (selectedIds.length === 0) return null

    // For single selection, we can just return the element's bounds directly
    // but getElementsBounds handles it correctly too.
    const allItems = { ...elements, ...placeholders }
    return getElementsBounds(selectedIds, allItems)
  }, [selectedIds, elements, placeholders])
}

// --- 3. Internal Canvas Context Hooks ---

export const useDominoDOMContext = () => useContext(DominoDOMContext)
export const useDominoRenderHooks = () => useContext(DominoRenderHooksContext)
