import { useCallback } from 'react'
import { v4 as uuidv4 } from 'uuid'
import { toast } from 'sonner'
import {
  imageMatting,
  imageOCR,
  recognizeImage,
  updateImageOCRText,
  segmentLayer,
  getSegmentLayerResult,
} from '../service/api'
import type {
  ImageOCRResponse,
  ImageOCRTextUpdateItem,
  RecognizedImageElement,
} from '../service/type'
import {
  type ImageElement,
  type PlaceholderElement,
  type SceneElement,
  type ArtboardElement,
  useDominoStoreInstance,
} from '../components/canvas'
import {
  MAX_IMAGE_SIZE_BYTES,
  MATTING_MIN_DIM,
  MATTING_MAX_DIM,
  NEED_COMPRESS_MAX_SIZE,
  NEED_COMPRESS_MIN_SIZE,
} from '../consts'
import {
  getImageFileSize,
  getImageDimension,
  getImageUrl,
  isValidImageFormat,
  isValidImageSize,
  manualPersistence,
} from '../utils/helper'

export function useImageEditActions(
  taskId: string,
  addElementToFlow: (elementTemplate: SceneElement) => SceneElement,
  onPartialRedraw?: (
    element: ImageElement,
    recognizedElements: readonly RecognizedImageElement[],
  ) => void,
) {
  const store = useDominoStoreInstance()

  const handleMatting = useCallback(
    async (element: ImageElement) => {
      const { originalWidth: w, originalHeight: h } = element

      // 1. Dimension check
      if (w < MATTING_MIN_DIM || h < MATTING_MIN_DIM) {
        toast.error('图片尺寸不能小于 32x32px')
        return
      }
      if (w > MATTING_MAX_DIM || h > MATTING_MAX_DIM) {
        toast.error('图片尺寸不能超过 4000x4000px')
        return
      }

      // 2. Size check
      const { updateElement } = store.getState()
      const fileSize = await getImageFileSize(element)
      if (!element.data?.size && fileSize > 0) {
        updateElement(element.id, { data: { ...element.data, size: fileSize } })
      }
      if (fileSize > MAX_IMAGE_SIZE_BYTES) {
        toast.error('图片大小不能超过 20MB')
        return
      }

      const placeholderId = uuidv4()
      const { removePlaceholder, updateElementUIState, addElement } =
        store.getState()

      // Immediately insert placeholder element for instant feedback
      const placeholder: PlaceholderElement = {
        id: placeholderId,
        type: 'placeholder',
        x: 0,
        y: 0,
        width: element.width,
        height: element.height,
        rotation: element.rotation || 0,
        originalWidth: element.width,
        originalHeight: element.height,
        label: '生成中',
      }
      const addedPlaceholder = addElementToFlow(
        placeholder,
      ) as PlaceholderElement
      updateElementUIState(placeholderId, { status: 'pending' })

      try {
        const res = await imageMatting({
          image_url: element.data?.path || element.id,
          task_id: taskId,
          compress: fileSize > NEED_COMPRESS_MIN_SIZE,
        })

        try {
          // Preload image
          const url = await getImageUrl(taskId, res.path)
          const { width, height } = await getImageDimension(url)

          // Replace placeholder with matting result
          removePlaceholder(placeholderId)
          const newImage: ImageElement = {
            ...addedPlaceholder,
            id: res.path,
            type: 'image',
            src: url,
            width,
            height,
            fileName: res.path.split('/').pop() || 'image.jpg',
            originalWidth: width,
            originalHeight: height,
            data: {
              path: res.path,
            },
          }
          addElement(newImage)
          updateElementUIState(res.path, { status: 'idle' })

          // Support background task persistence
          manualPersistence(taskId, store)
        } catch (e) {
          console.warn('Preload failed', e)
        }
      } catch (error) {
        console.error(error)
        removePlaceholder(placeholderId)
      }
    },
    [taskId, addElementToFlow, store],
  )

  const handlePartialRedraw = useCallback(
    async (element: ImageElement) => {
      if (!isValidImageFormat(element.fileName)) {
        toast.error('不合法的图片格式')
        return
      }
      if (!isValidImageSize(element.originalWidth, element.originalHeight)) {
        toast.error('图片尺寸不能超过 2160x3840px 或 3840x2160px')
        return
      }

      const { updateElement, updateElementUIState } = store.getState()
      const fileSize = await getImageFileSize(element)
      if (!element.data?.size && fileSize > 0) {
        updateElement(element.id, { data: { ...element.data, size: fileSize } })
      }
      if (fileSize >= MAX_IMAGE_SIZE_BYTES) {
        toast.error('图片大小不能超过 20MB')
        return
      }

      updateElementUIState(element.id, {
        status: 'pending',
        statusText: '识图中...',
      })

      try {
        const res = await recognizeImage({
          image_url: element.data?.path || element.id,
          task_id: taskId,
          width: element.originalWidth,
          height: element.originalHeight,
        })
        onPartialRedraw?.(element, res || [])
      } catch (err) {
        console.error('Failed to recognize image:', err)
      } finally {
        updateElementUIState(element.id, {
          status: 'idle',
        })
      }
    },
    [taskId, onPartialRedraw, store],
  )

  const handleEditText = useCallback(
    async (
      element: ImageElement,
      onOCRSuccess: (data: ImageOCRResponse) => void,
    ) => {
      if (!isValidImageFormat(element.fileName)) {
        toast.error('不合法的图片格式')
        return
      }
      if (!isValidImageSize(element.originalWidth, element.originalHeight)) {
        toast.error('图片尺寸不能超过 2160x3840px 或 3840x2160px')
        return
      }

      const { updateElement, updateElementUIState } = store.getState()
      const fileSize = await getImageFileSize(element)
      if (!element.data?.size && fileSize > 0) {
        updateElement(element.id, { data: { ...element.data, size: fileSize } })
      }
      if (fileSize >= MAX_IMAGE_SIZE_BYTES) {
        toast.error('图片大小不能超过 20MB')
        return
      }

      updateElementUIState(element.id, {
        status: 'pending',
        statusText: '正在提取文字',
      })

      const errorText = '没有提取到文字'

      try {
        const data = await imageOCR({
          image_url: element.data?.path || element.id,
          task_id: taskId,
        })
        if (data.length > 0) {
          onOCRSuccess(data)
        } else {
          toast.error(errorText)
        }
      } catch (error) {
        console.error(error)
        toast.error(errorText)
      } finally {
        updateElementUIState(element.id, { status: 'idle' })
      }
    },
    [taskId, store],
  )

  const handleConfirmEditText = useCallback(
    async (element: ImageElement, updatedList: ImageOCRTextUpdateItem[]) => {
      const placeholderId = uuidv4()
      const { removePlaceholder, updateElementUIState, addElement } =
        store.getState()

      // Insert new placeholder element into the flow
      const placeholder: PlaceholderElement = {
        id: placeholderId,
        type: 'placeholder',
        x: 0,
        y: 0,
        width: element.width,
        height: element.height,
        rotation: element.rotation || 0,
        originalWidth: element.width,
        originalHeight: element.height,
        label: '处理中...',
      }
      const addedPlaceholder = addElementToFlow(
        placeholder,
      ) as PlaceholderElement
      updateElementUIState(placeholderId, { status: 'pending' })

      try {
        const res = await updateImageOCRText({
          image_url: element.data?.path || element.id,
          texts: updatedList,
          task_id: taskId,
          compress: (element.data?.size ?? 0) > NEED_COMPRESS_MAX_SIZE,
        })

        // Preload next image
        try {
          const url = await getImageUrl(taskId, res.path)
          const { width, height } = await getImageDimension(url)

          // Replace placeholder with result
          removePlaceholder(placeholderId)
          const newImage: ImageElement = {
            ...addedPlaceholder,
            id: res.path,
            type: 'image',
            src: url,
            width,
            height,
            fileName: res.path.split('/').pop() || 'image.jpg',
            originalWidth: width,
            originalHeight: height,
            data: {
              path: res.path,
            },
          }
          addElement(newImage)
          updateElementUIState(res.path, { status: 'idle' })

          // Support background task persistence
          manualPersistence(taskId, store)
        } catch (e) {
          console.warn('Preload failed', e)
        }
      } catch (error) {
        console.error(error)
        removePlaceholder(placeholderId)
        toast.error('修改失败')
      }
    },
    [taskId, addElementToFlow, store],
  )

  const handleEditElements = useCallback(
    async (element: ImageElement) => {
      const { updateElementUIState, addElement, setSelectedIds } =
        store.getState()

      updateElementUIState(element.id, {
        status: 'pending',
        statusText: '正在分层...',
      })

      try {
        const taskRecordId = await segmentLayer({
          image_url: element.data?.path || element.id,
          task_id: taskId,
          width: element.originalWidth,
          height: element.originalHeight,
        })

        // Polling loop
        let task = await getSegmentLayerResult(taskRecordId)
        while (task.status === 'PROCESSING') {
          await new Promise(resolve => setTimeout(resolve, 2000))
          task = await getSegmentLayerResult(taskRecordId)
        }

        if (
          task.status === 'TIMEOUT' ||
          task.status === 'FAILED' ||
          !task.layers
        ) {
          throw new Error('分层任务执行失败')
        }

        const layersData = task.layers

        // 1. Prepare all layers (Sorted by layer_order from server)
        const allLayersData = layersData.map(layer => ({
          image: layer.image,
          line_rect: {
            x: layer.x,
            y: layer.y,
            width: layer.width,
            height: layer.height,
          },
          line_text: layer.desc,
          hideMetadata: layer.desc === 'background',
        }))

        // 2. Preload all layers and prepare IDs
        const layers = await Promise.all(
          allLayersData.map(async item => {
            const itemUrl = await getImageUrl(taskId, item.image.path)
            const childId = uuidv4()
            return { item, itemUrl, childId }
          }),
        )

        // 3. Create Artboard Template
        const artboardId = uuidv4()
        const artboardTemplate: ArtboardElement = {
          id: artboardId,
          type: 'artboard',
          name: `画板 - ${element.fileName}`,
          x: 0,
          y: 0,
          width: element.width,
          height: element.height,
          rotation: element.rotation || 0,
          originalWidth: element.originalWidth,
          originalHeight: element.originalHeight,
          background: '#FFFFFF',
          childrenIds: layers.map(l => l.childId),
        }

        // Add artboard to flow
        const addedArtboard = addElementToFlow(
          artboardTemplate,
        ) as ArtboardElement

        // 4. Add all child elements to store
        for (const layer of layers) {
          const { item, itemUrl, childId } = layer
          const childImage: ImageElement = {
            id: childId,
            type: 'image',
            x: item.line_rect.x,
            y: item.line_rect.y,
            width: item.line_rect.width,
            height: item.line_rect.height,
            rotation: 0,
            originalWidth: item.line_rect.width,
            originalHeight: item.line_rect.height,
            src: itemUrl,
            fileName: item.image.path.split('/').pop() || 'layer.png',
            parentId: artboardId,
            selectable: true,
            hideMetadata: item.hideMetadata,
            data: {
              path: item.image.path,
              text: item.line_text,
            },
          }
          addElement(childImage)
        }

        setSelectedIds([addedArtboard.id])

        // Support background task persistence
        manualPersistence(taskId, store)
      } catch (err) {
        console.error('Failed to segment text layer:', err)
        toast.error('修改失败')
      } finally {
        updateElementUIState(element.id, {
          status: 'idle',
          statusText: undefined,
        })
      }
    },
    [taskId, store, addElementToFlow],
  )

  return {
    handleMatting,
    handlePartialRedraw,
    handleEditText,
    handleConfirmEditText,
    handleEditElements,
  }
}
