import { useEffect, useCallback, useRef, useState } from 'react'
import { shallow } from 'zustand/shallow'
import {
  saveDomiBoardContent,
  getDomiBoardContent,
} from '../service/api'
import { useDominoStoreInstance } from '../components/canvas'
import type { SceneElement, DominoCanvasData } from '../components/canvas'

export function usePersistence(options: {
  taskId: string
  setLoading: (loading: boolean) => void
}) {
  const { taskId, setLoading } = options
  const store = useDominoStoreInstance()

  const isFirstLoad = useRef(true)
  const [initialized, setInitialized] = useState(false)

  // 任务切换时重置状态
  useEffect(() => {
    isFirstLoad.current = true
    setInitialized(false)
  }, [taskId])

  const loadBoard = useCallback(async () => {
    if (!taskId) {
      setLoading(false)
      setInitialized(true)
      return
    }
    const currentTaskId = taskId
    setLoading(true)

    try {
      const res = (await getDomiBoardContent(taskId)) as
        | DominoCanvasData
        | string

      if (taskId !== currentTaskId) return

      if (res) {
        try {
          const parsed = (
            typeof res === 'string' ? JSON.parse(res) : res
          ) as DominoCanvasData
          if (parsed && typeof parsed === 'object') {
            const { elements, elementOrder, createdAt, updatedAt } = parsed
            const state = store.getState()

            state.clearElements()
            Object.values(elements).forEach(el => {
              state.addElement(el)
            })
            // addElement might have added them in different order, so we overwrite it.
            store.setState({
              elementOrder,
              metadata: {
                createdAt: createdAt || Date.now(),
                updatedAt: updatedAt || Date.now(),
              },
            })

            state.resetHistory()

            setLoading(false)
            isFirstLoad.current = false
            setInitialized(true)
          }
        } catch (e) {
          console.error('Failed to parse saved DomiBoard content', e)
        }
      }
    } catch (e) {
      console.error('Failed to load DomiBoard content', e)
    } finally {
      if (taskId === currentTaskId) {
        if (isFirstLoad.current) {
          isFirstLoad.current = false
        }
        setLoading(false)
        setInitialized(true)
        store.getState().resetHistory()
      }
    }
  }, [taskId, setLoading])

  const saveTimerRef = useRef<NodeJS.Timeout | null>(null)

  // Auto-save logic
  useEffect(() => {
    let lastState = {
      elements: store.getState().elements,
      elementOrder: store.getState().elementOrder,
    }

    const unsubscribe = store.subscribe(state => {
      const curr = {
        elements: state.elements,
        elementOrder: state.elementOrder,
      }

      // Check if relevant state changed using shallow comparison
      if (shallow(lastState, curr)) return
      lastState = curr

      if (isFirstLoad.current || !taskId) return

      if (saveTimerRef.current) {
        clearTimeout(saveTimerRef.current)
      }

      saveTimerRef.current = setTimeout(async () => {
        try {
          const currentMetadata = store.getState().metadata || {}
          const createdAt = currentMetadata.createdAt || Date.now()
          const persistentElements: Record<string, SceneElement> = {}
          const persistentOrder: string[] = []

          Object.values(curr.elements).forEach(el => {
            if (el.type !== 'placeholder') {
              persistentElements[el.id] = el
            }
          })
          curr.elementOrder.forEach((id: string) => {
            if (curr.elements[id] && curr.elements[id].type !== 'placeholder') {
              persistentOrder.push(id)
            }
          })

          const persistenceData: DominoCanvasData = {
            elements: persistentElements,
            elementOrder: persistentOrder,
            createdAt,
            updatedAt: Date.now(),
          }
          await saveDomiBoardContent({
            task_id: taskId,
            data: persistenceData,
          })
        } catch (e) {
          console.error('Failed to auto-save DomiBoard content', e)
        }
      }, 2000) // 2 second debounce
    })

    return () => {
      unsubscribe()
      if (saveTimerRef.current) {
        clearTimeout(saveTimerRef.current)
      }
    }
  }, [taskId, store])

  return { loadBoard, initialized }
}
