import { useCallback, useEffect, useRef } from 'react'
import { v4 as uuidv4 } from 'uuid'
import { toast } from 'sonner'
import {
  type ImageElement,
  type SceneElement,
  type TextStyle,
  useDominoStoreInstance,
} from '../components/canvas'
import { MAX_IMAGE_SIZE_BYTES } from '../consts'
import {
  getImageDimension,
  isValidImageFormat,
  uploadImage,
  waitForElement,
} from '../utils/helper'

export function useElementActions(
  taskId: string,
  addElementToFlow: (elementTemplate: SceneElement) => SceneElement,
  scrollIntoView?: (elementId: string) => void,
) {
  const store = useDominoStoreInstance()

  const lastTextStyleRef = useRef<TextStyle>({
    fontSize: 48,
    color: '#000000',
    fontFamily: undefined,
    fontWeight: 'normal',
    fontStyle: 'normal',
    textAlign: 'left',
  })

  useEffect(() => {
    let lastSelection = store.getState().selectedIds
    return store.subscribe(state => {
      const selectedIds = state.selectedIds
      if (selectedIds === lastSelection) return
      lastSelection = selectedIds

      const lastId = selectedIds[selectedIds.length - 1]
      const el = state.elements[lastId]
      if (el?.type === 'text') {
        const textEl = el
        lastTextStyleRef.current = {
          fontSize: textEl.fontSize,
          fontWeight: textEl.fontWeight,
          color: textEl.color,
          fontFamily: textEl.fontFamily,
          lineHeight: textEl.lineHeight,
          textAlign: textEl.textAlign,
          fontStyle: textEl.fontStyle,
        }
      }
    })
  }, [store])

  const handleAddArtboard = useCallback(() => {
    const id = uuidv4()
    addElementToFlow({
      id,
      type: 'artboard',
      x: 0,
      y: 0,
      width: 750,
      height: 1750,
      rotation: 0,
      originalWidth: 750,
      originalHeight: 1750,
      childrenIds: [],
      background: '#FFFFFF',
      lockAspectRatio: false,
    })
    scrollIntoView?.(id)
  }, [addElementToFlow, scrollIntoView])

  const handleAddText = useCallback(
    (options?: { content?: string; style?: Partial<TextStyle> }) => {
      const id = uuidv4()
      const lastTextStyle = lastTextStyleRef.current
      const addedElement = addElementToFlow({
        id,
        type: 'text',
        fontSize: 48,
        x: 0,
        y: 0,
        width: 0,
        height: 100,
        rotation: 0,
        originalWidth: 200,
        originalHeight: 100,
        content: options?.content || 'New Text',
        resize: 'horizontal',
        ...lastTextStyle,
        ...options?.style,
      })

      scrollIntoView?.(id)
      // 等待 DOM 渲染后再选中，确保能获取到正确的元素尺寸
      waitForElement(id).then(() => {
        store.getState().setSelectedIds([id])
      })
      return addedElement
    },
    [addElementToFlow, scrollIntoView, store],
  )

  const handleAddImageFromFile = useCallback(
    async (file: File) => {
      const { name, type } = file
      const isImage = type.startsWith('image/')
      if (!isImage && !isValidImageFormat(name)) {
        toast.error('不合法的图片格式')
        return
      }

      if (file.size >= MAX_IMAGE_SIZE_BYTES) {
        toast.error('图片大小不能超过 20MB')
        return
      }

      const objectUrl = URL.createObjectURL(file)
      const { removeElement, addElement, updateElementUIState } =
        store.getState()
      const tempId = uuidv4()

      try {
        const { width, height } = await getImageDimension(objectUrl)

        // Optimistic update
        const optimisticImage: ImageElement = {
          id: tempId,
          type: 'image',
          x: 0,
          y: 0,
          width,
          height,
          rotation: 0,
          src: objectUrl,
          fileName: name,
          originalWidth: width,
          originalHeight: height,
          data: {
            size: file.size,
          },
        }
        const addedElement = addElementToFlow(optimisticImage) as ImageElement
        updateElementUIState(tempId, {
          status: 'pending',
          statusText: '处理中...',
        })
        scrollIntoView?.(tempId)

        let url = objectUrl
        let file_path = ''
        let size = file.size
        try {
          // Upload
          const res = await uploadImage(taskId, file)
          url = res.url
          file_path = res.file_path
          size = res.size
        } catch (e) {
          console.warn('Preload failed', e)
        }

        // Replace optimistic image with permanent one
        removeElement(tempId)
        const newImage: ImageElement = {
          ...addedElement,
          id: file_path,
          src: url,
          data: {
            path: file_path,
            size,
          },
        }
        addElement(newImage)
        updateElementUIState(file_path, {
          status: 'idle',
        })
        store.getState().setFocusedElementId(file_path)
        scrollIntoView?.(file_path)

        if (url !== objectUrl) {
          URL.revokeObjectURL(objectUrl)
        }
      } catch (error) {
        console.error('Failed to add image:', error)
        removeElement(tempId)
        toast.error('添加失败')
        URL.revokeObjectURL(objectUrl)
      }
    },
    [taskId, addElementToFlow, scrollIntoView, store],
  )

  const handleAddImage = useCallback(() => {
    const input = document.createElement('input')
    input.type = 'file'
    input.accept = 'image/*'
    input.onchange = async e => {
      const file = (e.target as HTMLInputElement).files?.[0]
      if (!file) return
      handleAddImageFromFile(file)
    }
    input.click()
  }, [handleAddImageFromFile])

  const handleDeleteElements = useCallback(
    async (ids: string[]) => {
      if (ids.length === 0) return
      const { removeElement, takeSnapshot } = store.getState()
      takeSnapshot()
      ids.forEach(id => removeElement(id))
    },
    [store],
  )

  return {
    handleAddArtboard,
    handleAddImage,
    handleAddImageFromFile,
    handleAddText,
    handleDeleteElements,
  }
}
