import { nextTick, ref, toRaw } from 'vue'
import { showErrorAlert } from '~/composables/useErrorNotice'

const CONTEXT_MENU_MARGIN = 8

const initialContextMenu = () => ({
  visible: false,
  x: 0,
  y: 0,
  message: null,
  kind: '',
  disabled: false,
  editStatus: null,
  editStatusLoading: false
})

const initialMessageEditModal = () => ({
  open: false,
  loading: false,
  saving: false,
  error: '',
  mode: 'content',
  sessionId: '',
  messageId: '',
  draft: '',
  rawRow: null
})

const initialMessageFieldsModal = () => ({
  open: false,
  loading: false,
  saving: false,
  error: '',
  sessionId: '',
  messageId: '',
  unsafe: false,
  editsJson: '',
  rawRow: null
})

export const useChatEditing = ({
  api,
  selectedAccount,
  selectedContact,
  refreshSelectedMessages,
  normalizeMessage,
  allMessages,
  locateMessageByServerId
}) => {
  const contextMenu = ref(initialContextMenu())
  const contextMenuElement = ref(null)
  const messageEditModal = ref(initialMessageEditModal())
  const messageFieldsModal = ref(initialMessageFieldsModal())

  const closeContextMenu = () => {
    contextMenu.value = initialContextMenu()
  }

  const repositionContextMenu = () => {
    if (!process.client || !contextMenu.value.visible) return
    const menuEl = contextMenuElement.value
    if (!menuEl) return

    const rect = menuEl.getBoundingClientRect()
    const viewportWidth = Math.max(window.innerWidth || 0, document.documentElement?.clientWidth || 0)
    const viewportHeight = Math.max(window.innerHeight || 0, document.documentElement?.clientHeight || 0)
    if (!viewportWidth || !viewportHeight) return

    const maxX = Math.max(CONTEXT_MENU_MARGIN, viewportWidth - rect.width - CONTEXT_MENU_MARGIN)
    const maxY = Math.max(CONTEXT_MENU_MARGIN, viewportHeight - rect.height - CONTEXT_MENU_MARGIN)
    const currentX = Number(contextMenu.value.x || 0)
    const currentY = Number(contextMenu.value.y || 0)
    const nextX = Math.min(Math.max(currentX, CONTEXT_MENU_MARGIN), maxX)
    const nextY = Math.min(Math.max(currentY, CONTEXT_MENU_MARGIN), maxY)

    if (nextX !== currentX || nextY !== currentY) {
      contextMenu.value = {
        ...contextMenu.value,
        x: nextX,
        y: nextY
      }
    }
  }

  const scheduleContextMenuReposition = () => {
    if (!process.client) return
    void nextTick(() => {
      const run = () => repositionContextMenu()
      if (typeof window.requestAnimationFrame === 'function') {
        window.requestAnimationFrame(run)
      } else {
        run()
      }
    })
  }

  const loadContextMenuEditStatus = async (params) => {
    if (!process.client) return
    const account = String(params?.account || '').trim()
    const username = String(params?.username || '').trim()
    const messageId = String(params?.message_id || '').trim()
    if (!account || !username || !messageId) {
      contextMenu.value.editStatusLoading = false
      return
    }

    try {
      const response = await api.getChatEditStatus({ account, username, message_id: messageId })
      const current = String(contextMenu.value?.message?.id || '').trim()
      if (contextMenu.value.visible && current === messageId) {
        contextMenu.value.editStatus = response || { modified: false }
        scheduleContextMenuReposition()
      }
    } catch {
      const current = String(contextMenu.value?.message?.id || '').trim()
      if (contextMenu.value.visible && current === messageId) {
        contextMenu.value.editStatus = null
        scheduleContextMenuReposition()
      }
    } finally {
      const current = String(contextMenu.value?.message?.id || '').trim()
      if (contextMenu.value.visible && current === messageId) {
        contextMenu.value.editStatusLoading = false
        scheduleContextMenuReposition()
      }
    }
  }

  const openMediaContextMenu = (event, message, kind) => {
    if (!process.client) return
    event.preventDefault()
    event.stopPropagation()

    let actualKind = kind
    let disabled = true
    if (kind === 'voice') {
      disabled = !(message?.serverIdStr || message?.serverId)
    } else if (kind === 'file') {
      disabled = !message?.fileMd5
    } else if (kind === 'image') {
      disabled = !(message?.imageMd5 || message?.imageFileId)
    } else if (kind === 'emoji') {
      disabled = !message?.emojiMd5
    } else if (kind === 'video') {
      if (message?.videoMd5 || message?.videoFileId) {
        disabled = false
        actualKind = 'video'
      } else if (message?.videoThumbMd5 || message?.videoThumbFileId) {
        disabled = false
        actualKind = 'video_thumb'
      }
    }

    contextMenu.value = {
      visible: true,
      x: event.clientX,
      y: event.clientY,
      message,
      kind: actualKind,
      disabled,
      editStatus: null,
      editStatusLoading: false
    }

    try {
      const account = String(selectedAccount.value || '').trim()
      const username = String(selectedContact.value?.username || '').trim()
      const messageId = String(message?.id || '').trim()
      if (account && username && messageId) {
        contextMenu.value.editStatusLoading = true
        void loadContextMenuEditStatus({ account, username, message_id: messageId })
      }
    } catch {}

    scheduleContextMenuReposition()
  }

  const prettyJson = (value) => {
    try {
      return JSON.stringify(value ?? null, null, 2)
    } catch {
      return String(value ?? '')
    }
  }

  const isLikelyTextMessage = (message) => {
    if (!message) return false
    const renderType = String(message?.renderType || '').trim()
    if (renderType && renderType !== 'text') return false
    if (message?.imageUrl || message?.emojiUrl || message?.videoUrl || message?.voiceUrl) return false
    return true
  }

  const closeMessageEditModal = () => {
    messageEditModal.value = initialMessageEditModal()
  }

  const openMessageEditModal = async ({ message, mode }) => {
    if (!process.client) return
    const account = String(selectedAccount.value || '').trim()
    const sessionId = String(selectedContact.value?.username || '').trim()
    const messageId = String(message?.id || '').trim()
    if (!account || !sessionId || !messageId) return

    const resolvedMode = mode === 'raw' ? 'raw' : 'content'
    const initialDraft = resolvedMode === 'content'
      ? (typeof message?.content === 'string' ? message.content : String(message?.content ?? ''))
      : ''

    messageEditModal.value = {
      open: true,
      loading: true,
      saving: false,
      error: '',
      mode: resolvedMode,
      sessionId,
      messageId,
      draft: initialDraft,
      rawRow: null
    }

    try {
      const response = await api.getChatMessageRaw({ account, username: sessionId, message_id: messageId })
      const row = response?.row || null
      const rawContent = row?.message_content
      const rawDraft = typeof rawContent === 'string' ? rawContent : String(rawContent ?? '')
      const draft = resolvedMode === 'raw' ? rawDraft : messageEditModal.value.draft
      messageEditModal.value = { ...messageEditModal.value, loading: false, rawRow: row, draft }
    } catch (error) {
      messageEditModal.value = { ...messageEditModal.value, loading: false, error: error?.message || '加载失败' }
    }
  }

  const saveMessageEditModal = async () => {
    if (!process.client) return
    if (messageEditModal.value.saving || messageEditModal.value.loading) return

    const account = String(selectedAccount.value || '').trim()
    const sessionId = String(messageEditModal.value.sessionId || '').trim()
    const messageId = String(messageEditModal.value.messageId || '').trim()
    if (!account || !sessionId || !messageId) return

    messageEditModal.value = { ...messageEditModal.value, saving: true, error: '' }
    try {
      const response = await api.editChatMessage({
        account,
        session_id: sessionId,
        message_id: messageId,
        edits: {
          message_content: String(messageEditModal.value.draft ?? '')
        },
        unsafe: false
      })

      if (response?.updated_message) {
        try {
          const updated = normalizeMessage(response.updated_message)
          const username = String(selectedContact.value?.username || '').trim()
          const list = allMessages.value[username] || []
          const index = list.findIndex((message) => String(message?.id || '') === String(updated?.id || ''))
          if (index >= 0) {
            const next = [...list]
            next[index] = updated
            allMessages.value = { ...allMessages.value, [username]: next }
          } else {
            await refreshSelectedMessages()
          }
        } catch {
          await refreshSelectedMessages()
        }
      } else {
        await refreshSelectedMessages()
      }

      closeMessageEditModal()
    } catch (error) {
      messageEditModal.value = { ...messageEditModal.value, saving: false, error: error?.message || '保存失败' }
      return
    } finally {
      messageEditModal.value = { ...messageEditModal.value, saving: false }
    }
  }

  const closeMessageFieldsModal = () => {
    messageFieldsModal.value = initialMessageFieldsModal()
  }

  const openMessageFieldsModal = async (message) => {
    if (!process.client) return
    const account = String(selectedAccount.value || '').trim()
    const sessionId = String(selectedContact.value?.username || '').trim()
    const messageId = String(message?.id || '').trim()
    if (!account || !sessionId || !messageId) return

    messageFieldsModal.value = {
      open: true,
      loading: true,
      saving: false,
      error: '',
      sessionId,
      messageId,
      unsafe: false,
      editsJson: '',
      rawRow: null
    }

    try {
      const response = await api.getChatMessageRaw({ account, username: sessionId, message_id: messageId })
      const row = response?.row || null
      const seed = {}
      for (const key of ['message_content', 'local_type', 'create_time', 'server_id', 'origin_source', 'source']) {
        if (row && Object.prototype.hasOwnProperty.call(row, key)) seed[key] = row[key]
      }
      messageFieldsModal.value = {
        ...messageFieldsModal.value,
        loading: false,
        rawRow: row,
        editsJson: JSON.stringify(seed, null, 2)
      }
    } catch (error) {
      messageFieldsModal.value = { ...messageFieldsModal.value, loading: false, error: error?.message || '加载失败' }
    }
  }

  const saveMessageFieldsModal = async () => {
    if (!process.client) return
    if (messageFieldsModal.value.saving || messageFieldsModal.value.loading) return

    const account = String(selectedAccount.value || '').trim()
    const sessionId = String(messageFieldsModal.value.sessionId || '').trim()
    const messageId = String(messageFieldsModal.value.messageId || '').trim()
    if (!account || !sessionId || !messageId) return

    let edits = null
    try {
      edits = JSON.parse(String(messageFieldsModal.value.editsJson || '').trim() || 'null')
    } catch {
      messageFieldsModal.value = { ...messageFieldsModal.value, error: 'JSON 格式错误' }
      return
    }
    if (!edits || typeof edits !== 'object' || Array.isArray(edits)) {
      messageFieldsModal.value = { ...messageFieldsModal.value, error: 'edits 必须是 JSON 对象' }
      return
    }
    if (!Object.keys(edits).length) {
      messageFieldsModal.value = { ...messageFieldsModal.value, error: 'edits 不能为空' }
      return
    }

    messageFieldsModal.value = { ...messageFieldsModal.value, saving: true, error: '' }
    try {
      await api.editChatMessage({
        account,
        session_id: sessionId,
        message_id: messageId,
        edits,
        unsafe: !!messageFieldsModal.value.unsafe
      })
      await refreshSelectedMessages()
      closeMessageFieldsModal()
    } catch (error) {
      messageFieldsModal.value = { ...messageFieldsModal.value, saving: false, error: error?.message || '保存失败' }
      return
    } finally {
      messageFieldsModal.value = { ...messageFieldsModal.value, saving: false }
    }
  }

  const copyTextToClipboard = async (text) => {
    if (!process.client) return false

    const value = String(text ?? '').trim()
    if (!value) return false

    try {
      await navigator.clipboard.writeText(value)
      return true
    } catch {}

    try {
      const element = document.createElement('textarea')
      element.value = value
      element.setAttribute('readonly', 'true')
      element.style.position = 'fixed'
      element.style.left = '-9999px'
      element.style.top = '-9999px'
      document.body.appendChild(element)
      element.select()
      const ok = document.execCommand('copy')
      document.body.removeChild(element)
      if (ok) return true
    } catch {}

    try {
      window.prompt('复制内容：', value)
      return true
    } catch {
      return false
    }
  }

  const onCopyMessageTextClick = async () => {
    if (!process.client) return
    const message = contextMenu.value.message
    if (!message) return
    try {
      const text = String(message?.content || '').trim()
      if (!text) {
        window.alert('该消息没有可复制的文本')
        return
      }
      const ok = await copyTextToClipboard(text)
      if (!ok) showErrorAlert('复制失败：无法写入剪贴板')
    } catch {
      showErrorAlert('复制失败')
    } finally {
      closeContextMenu()
    }
  }

  const onCopyMessageJsonClick = async () => {
    if (!process.client) return
    const message = contextMenu.value.message
    if (!message) return
    try {
      const raw = toRaw(message) || message
      const json = JSON.stringify(raw, (_key, value) => (typeof value === 'bigint' ? value.toString() : value), 2)
      const ok = await copyTextToClipboard(json)
      if (!ok) showErrorAlert('复制失败：无法写入剪贴板')
    } catch {
      showErrorAlert('复制失败')
    } finally {
      closeContextMenu()
    }
  }

  const onOpenFolderClick = async () => {
    if (contextMenu.value.disabled) return
    const message = contextMenu.value.message
    const kind = contextMenu.value.kind

    try {
      if (!selectedAccount.value || !selectedContact.value?.username) return

      const params = {
        account: selectedAccount.value,
        username: selectedContact.value.username,
        kind
      }

      if (kind === 'voice') {
        params.server_id = message.serverIdStr || message.serverId
      } else if (kind === 'file') {
        params.md5 = message.fileMd5
      } else if (kind === 'image') {
        if (message.imageMd5) params.md5 = message.imageMd5
        else if (message.imageFileId) params.file_id = message.imageFileId
      } else if (kind === 'emoji') {
        params.md5 = message.emojiMd5
      } else if (kind === 'video') {
        params.md5 = message.videoMd5
        if (message.videoFileId) params.file_id = message.videoFileId
      } else if (kind === 'video_thumb') {
        params.md5 = message.videoThumbMd5
        if (message.videoThumbFileId) params.file_id = message.videoThumbFileId
      }

      await api.openChatMediaFolder(params)
    } finally {
      closeContextMenu()
    }
  }

  const onEditMessageClick = async () => {
    const message = contextMenu.value.message
    if (!message) return
    const mode = isLikelyTextMessage(message) ? 'content' : 'raw'
    closeContextMenu()
    await openMessageEditModal({ message, mode })
  }

  const onEditMessageFieldsClick = async () => {
    const message = contextMenu.value.message
    if (!message) return
    closeContextMenu()
    await openMessageFieldsModal(message)
  }

  const onResetEditedMessageClick = async () => {
    if (!process.client) return
    const message = contextMenu.value.message
    const account = String(selectedAccount.value || '').trim()
    const sessionId = String(selectedContact.value?.username || '').trim()
    const messageId = String(message?.id || '').trim()
    if (!message || !account || !sessionId || !messageId) return

    const ok = window.confirm('确认恢复该条消息到首次快照吗？')
    if (!ok) return

    try {
      await api.resetChatEditedMessage({ account, session_id: sessionId, message_id: messageId })
      closeContextMenu()
      await refreshSelectedMessages()
    } catch (error) {
      showErrorAlert(error?.message || '恢复失败')
    } finally {
      closeContextMenu()
    }
  }

  const onRepairMessageSenderAsMeClick = async () => {
    if (!process.client) return
    const message = contextMenu.value.message
    const account = String(selectedAccount.value || '').trim()
    const sessionId = String(selectedContact.value?.username || '').trim()
    const messageId = String(message?.id || '').trim()
    if (!message || !account || !sessionId || !messageId) return

    const ok = window.confirm('确认将该消息修复为“我发送”吗？这会修改 real_sender_id 字段。')
    if (!ok) return

    try {
      await api.repairChatMessageSender({ account, session_id: sessionId, message_id: messageId, mode: 'me' })
      closeContextMenu()
      await refreshSelectedMessages()
    } catch (error) {
      showErrorAlert(error?.message || '修复失败')
    } finally {
      closeContextMenu()
    }
  }

  const onFlipWechatMessageDirectionClick = async () => {
    if (!process.client) return
    const message = contextMenu.value.message
    const account = String(selectedAccount.value || '').trim()
    const sessionId = String(selectedContact.value?.username || '').trim()
    const messageId = String(message?.id || '').trim()
    if (!message || !account || !sessionId || !messageId) return

    const ok = window.confirm(
      '确认反转该消息在微信客户端的左右气泡位置吗？\n\n这会修改 packed_info_data 字段（有风险）。\n可通过“恢复原消息”撤销。'
    )
    if (!ok) return

    try {
      await api.flipChatMessageDirection({ account, session_id: sessionId, message_id: messageId })
      closeContextMenu()
      await refreshSelectedMessages()
    } catch (error) {
      showErrorAlert(error?.message || '反转失败')
    } finally {
      closeContextMenu()
    }
  }

  const onLocateQuotedMessageClick = async () => {
    const message = contextMenu.value.message
    if (!message?.quoteServerId) return
    closeContextMenu()
    const ok = await locateMessageByServerId(message.quoteServerId)
    if (!ok && process.client) {
      showErrorAlert('定位引用消息失败')
    }
  }

  return {
    contextMenu,
    contextMenuElement,
    messageEditModal,
    messageFieldsModal,
    closeContextMenu,
    openMediaContextMenu,
    prettyJson,
    isLikelyTextMessage,
    closeMessageEditModal,
    openMessageEditModal,
    saveMessageEditModal,
    closeMessageFieldsModal,
    openMessageFieldsModal,
    saveMessageFieldsModal,
    copyTextToClipboard,
    onCopyMessageTextClick,
    onCopyMessageJsonClick,
    onOpenFolderClick,
    onEditMessageClick,
    onEditMessageFieldsClick,
    onResetEditedMessageClick,
    onRepairMessageSenderAsMeClick,
    onFlipWechatMessageDirectionClick,
    onLocateQuotedMessageClick
  }
}
