import type { CSSProperties } from 'react'
import React, {
  memo,
  useRef,
  useEffect,
  useCallback,
  useMemo,
  useState,
} from 'react'
import { v4 as uuidv4 } from 'uuid'
import { toast } from 'sonner'
import type {
  SimpleRect,
  RecognizedImageElement,
} from '../../service/type'
import { redrawImage } from '../../service/api'
import { Button } from '../ui/button'
import { cn } from '@/utils/cn'
import { useDominoStore, useDominoStoreInstance, DominoAnchor } from '../canvas'
import type { ImageElement, SceneElement, PlaceholderElement } from '../canvas'
import {
  flyParabola,
  getImageDimension,
  getImageUrl,
  manualPersistence,
} from '../../utils/helper'
import { NEED_COMPRESS_MAX_SIZE } from '../../consts'
import type { InlineMarkEditorRef } from './inline-mark-editor'
import { InlineMarkEditor } from './inline-mark-editor'

export interface MarkWithMetadata extends SimpleRect {
  index: number
  elementName?: string
  elementType?: string
  clickX: number
  clickY: number
}

export interface RedrawState {
  marks: MarkWithMetadata[]
  inputValue: string
  recognizedElements: RecognizedImageElement[]
  docJson?: any
}

export interface ImageRedrawEditorProps {
  className?: string
  style?: CSSProperties
  element: ImageElement
  maxMarkCount?: number
  onFinish?: () => void
  addElementToFlow: (elementTemplate: SceneElement) => SceneElement
  redrawState: RedrawState
  showToolbar: boolean
  containerRef: React.RefObject<HTMLElement | null>
  taskId: string
}

function ImageRedrawEditor(props: ImageRedrawEditorProps) {
  const {
    element,
    className,
    style,
    onFinish,
    maxMarkCount = 10,
    addElementToFlow,
    redrawState,
    showToolbar,
    containerRef,
    taskId,
  } = props
  const store = useDominoStoreInstance()
  const editorRef = useRef<InlineMarkEditorRef>(null)
  const svgRef = useRef<SVGSVGElement>(null)
  const [isDebug, setIsDebug] = useState(false)

  const { marks, inputValue, recognizedElements, docJson } = redrawState

  const isFull = marks.length >= maxMarkCount

  const updateRedrawState = useCallback(
    (updates: Partial<RedrawState>) => {
      const { updateElementUIState } = store.getState()
      updateElementUIState(element.id, {
        redrawState: {
          ...redrawState,
          ...updates,
        },
      })
    },
    [element.id, redrawState, store],
  )

  const { viewport } = useDominoStore(s => ({
    viewport: s.viewport,
  }))
  const { x: vx, y: vy, scale: vs } = viewport
  const {
    x,
    y,
    width,
    height,
    rotation = 0,
    originalWidth = 0,
    originalHeight = 0,
  } = element

  const viewBox = useMemo<[number, number, number, number]>(
    () => [0, 0, originalWidth || width, originalHeight || height],
    [originalWidth, width, originalHeight, height],
  )

  const handleImageClick = useCallback(
    (px: number, py: number, screenPoint: { x: number; y: number }) => {
      if (isFull) return

      // 1. 寻找被点击位置所属的识别区域（仅用于获取语义名称，不用于定位）
      const foundElement = [...recognizedElements]
        .filter(
          el =>
            px >= el.x && px <= el.x + el.w && py >= el.y && py <= el.y + el.h,
        )
        .sort((a, b) => a.w * a.h - b.w * b.h)[0]

      // 2. 构造标记数据
      const nextIndex = marks.length + 1
      const markW = 40 // 回退标记块宽度
      const markH = 40 // 回退标记块高度

      const markData: MarkWithMetadata = {
        x: foundElement ? foundElement.x : px - markW / 2,
        y: foundElement ? foundElement.y : py - markH / 2,
        width: foundElement ? foundElement.w : markW,
        height: foundElement ? foundElement.h : markH,
        index: nextIndex,
        elementName: foundElement?.element,
        elementType: foundElement?.type,
        clickX: px,
        clickY: py,
      }

      // 3. 插入编辑器节点
      editorRef.current?.insertMark(markData)

      // 4. 触发飞入动画
      const from = { x: screenPoint.x, y: screenPoint.y }
      requestAnimationFrame(() => {
        const to = document
          .querySelector(`.pe-image-mark[data-index="${nextIndex}"]`)
          ?.getBoundingClientRect()
        if (to) flyParabola(nextIndex, from, to)
      })
    },
    [
      isFull,
      recognizedElements,
      marks.length,
      viewBox,
      element.src,
      flyParabola,
    ],
  )

  useEffect(() => {
    const onPointerDown = (e: PointerEvent) => {
      if (!showToolbar) return
      // 检查点击是否发生在重绘编辑器的 UI 上（如工具栏、输入框）
      if ((e.target as HTMLElement).closest('.pe-image-redraw-ui')) return

      const svg = svgRef.current
      if (!svg) return

      const pt = svg.createSVGPoint()
      pt.x = e.clientX
      pt.y = e.clientY
      const ctm = svg.getScreenCTM()
      if (!ctm) return
      const { x: px, y: py } = pt.matrixTransform(ctm.inverse())

      // 检查点击是否落在图片有效像素范围内
      if (px >= 0 && px <= viewBox[2] && py >= 0 && py <= viewBox[3]) {
        // 如果是左键点击且没有按下修饰键，则视为添加标号
        if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey) {
          handleImageClick(px, py, { x: e.clientX, y: e.clientY })
          // 阻止事件冒泡到画布，防止选择状态被改变（例如因点击层级关系导致的误判）
          e.stopPropagation()
          e.preventDefault()
        }
      }
    }

    window.addEventListener('pointerdown', onPointerDown, { capture: true })
    return () => {
      window.removeEventListener('pointerdown', onPointerDown, {
        capture: true,
      })
    }
  }, [handleImageClick, viewBox, showToolbar])

  const handleCancel = () => {
    onFinish?.()
  }

  const handleConfirm = async (e: React.KeyboardEvent | React.MouseEvent) => {
    e.stopPropagation()

    if (e instanceof KeyboardEvent && e.shiftKey) return

    if (!inputValue || !marks.length) return

    const placeholderId = uuidv4()
    const placeholderElement: 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 placeholder = addElementToFlow(placeholderElement)
    store.getState().updateElementUIState(placeholderId, {
      status: 'pending',
    })
    onFinish?.()

    try {
      const result = await redrawImage({
        image_url: element.data?.path || element.id,
        prompt: inputValue,
        task_id: taskId,
        compress: (element.data?.size ?? 0) > NEED_COMPRESS_MAX_SIZE,
      })

      const url = await getImageUrl(taskId, result.path)
      const { width, height } = await getImageDimension(url)

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

      // Replace placeholder with final result
      removePlaceholder(placeholderId)

      const finalPath = result.path || result.url
      if (!finalPath) {
        throw new Error('No path or URL returned from redraw')
      }

      const newImage: ImageElement = {
        ...placeholder,
        id: finalPath,
        type: 'image',
        src: url,
        width,
        height,
        originalWidth: width,
        originalHeight: height,
        fileName: result.file_name || element.fileName,
        data: {
          path: finalPath,
        },
      }

      addElement(newImage)

      updateElementUIState(finalPath, {
        status: 'idle',
        statusText: undefined,
      })

      // Support background task persistence
      manualPersistence(taskId, store)

      toast.success('重绘完成')
    } catch (e) {
      toast.error('对不起，处理失败')
      console.error(e)
      const { removePlaceholder } = store.getState()
      removePlaceholder(placeholderId)
    }
  }

  return (
    <div
      className={cn(
        'image-redraw-editor absolute inset-0 z-[70] pointer-events-none',
        className,
      )}
      style={style}
    >
      {/* Positioned Editing Box (Sticks to Canvas Image) */}
      <div
        className='absolute pointer-events-none'
        style={{
          left: x * vs + vx,
          top: y * vs + vy,
          width: width * vs,
          height: height * vs,
          transform: `rotate(${rotation}deg)`,
          transformOrigin: '50% 50%',
        }}
      >
        {/* Layer 1: Coordinate Reference (Invisible and Non-Blocking) */}
        <svg
          ref={svgRef}
          className='absolute inset-0 w-full h-full select-none pointer-events-none'
          viewBox={viewBox?.join(' ')}
        >
          <rect width='100%' height='100%' fill='transparent' />
          {isDebug &&
            recognizedElements.map((el, i) => (
              <g key={i}>
                <rect
                  x={el.x}
                  y={el.y}
                  width={el.w}
                  height={el.h}
                  fill='rgba(255, 0, 0, 0.1)'
                  stroke='red'
                  strokeWidth='1'
                  style={{ pointerEvents: 'none', userSelect: 'none' }}
                />
                <text
                  x={el.x + 4 / vs}
                  y={el.y + 12 / vs}
                  fill={'rgba(255, 0, 0, 0.6)'}
                  fontSize={10 / vs}
                  style={{ pointerEvents: 'none', userSelect: 'none' }}
                >
                  {el.element}
                </text>
              </g>
            ))}
        </svg>

        {/* Layer 2: Display Layer (HTML-based markers) */}
        <div className='absolute inset-0 flex items-center justify-center pointer-events-none'>
          {/* 这里通过 aspect-ratio 模拟图片 object-contain 的实际渲染区域 */}
          <div
            className='relative pointer-events-none'
            style={{
              width: '100%',
              height: '100%',
              maxWidth: '100%',
              maxHeight: '100%',
              aspectRatio: `${viewBox[2]} / ${viewBox[3]}`,
            }}
          >
            {marks.map(mark => {
              // 标号位置优先以精确点击位置为准，无则取区域中心
              const cx = mark.clickX ?? mark.x + mark.width / 2
              const cy = mark.clickY ?? mark.y + mark.height / 2
              const left = (cx / viewBox[2]) * 100
              const top = (cy / viewBox[3]) * 100

              return (
                <div
                  key={mark.index}
                  className={cn(
                    'image-redraw-editor-image-mark',
                    'absolute flex items-center justify-center rounded-full border-2 border-white',
                    'bg-primary text-primary-foreground font-bold shadow-[0_2px_10px_rgba(16,37,51,0.24)]',
                    'z-10',
                  )}
                  style={{
                    left: `${left}%`,
                    top: `${top}%`,
                    width: '22px',
                    height: '22px',
                    fontSize: '12px',
                    transform: `translate(-50%, -50%) rotate(${-rotation}deg)`,
                    zIndex: 20,
                    pointerEvents: 'none',
                  }}
                >
                  {mark.index}
                </div>
              )
            })}
          </div>
        </div>
      </div>

      {showToolbar && (
        <DominoAnchor
          id={element.id}
          containerRef={containerRef}
          placement='bottom'
          className={cn(
            'pe-image-redraw-input',
            'z-3 flex gap-[2px] p-[4px] rounded-[12px]',
            'editor-floating-panel-soft',
            // 默认响应点击
            'pointer-events-auto',
            // 状态联动：当画布处于特定交互状态时，强制禁止 UI 拦截事件
            // 1. 兄弟选择器联动 (Canvas 是前置兄弟)
            '[.is-panning~&]:!pointer-events-none [.is-zooming~&]:!pointer-events-none',
            '[.is-dragging~&]:!pointer-events-none',
            // 2. 祖先组状态联动 (DomiBoard 是 group)
            'group-has-[.is-panning]:!pointer-events-none group-has-[.is-zooming]:!pointer-events-none',
            'group-has-[.is-dragging]:!pointer-events-none',
          )}
        >
          <div className='editor-toolbar-chip flex flex-1 items-center rounded-[8px] px-[6px]'>
            <InlineMarkEditor
              key={element.id}
              className='flex w-[320px] max-h-[180px] text-[14px] font-medium'
              ref={editorRef}
              initialHtml={docJson?.html}
              placeholder='请点击标记你想要修改的内容'
              onChange={(
                val: string,
                newMarks: MarkWithMetadata[],
                html: string,
              ) => {
                updateRedrawState({
                  inputValue: val,
                  marks: newMarks,
                  docJson: { html },
                })
              }}
              onEnter={handleConfirm}
            />
          </div>
          <div className='flex gap-[2px] items-end justify-center pb-4px'>
            <Button size='sm' variant='outline' onClick={handleCancel}>
              取消
            </Button>
            <Button
              size='sm'
              variant='default'
              disabled={!inputValue || !marks.length}
              onClick={handleConfirm}
            >
              确认
            </Button>
          </div>
        </DominoAnchor>
      )}
    </div>
  )
}

export default memo(ImageRedrawEditor)
