import type { Bot, Context } from 'grammy'
import { InputFile } from 'grammy'
import { HTTPClient } from '@/http'
import { getDefaultAgentId } from '@/app/api/nova-config'
import { getConversationId, setConversationId } from './user-store'
import { sendMessageAndWaitResponse } from '@/remote-control/shared/nova-bridge'
import { uploadBotAttachments, type BotAttachment } from '@/remote-control/shared/file-uploader'
import { BotLogger } from '@/remote-control/shared/logger'

const oapiClient = new HTTPClient({
  baseURL: process.env.NOVA_BASE_URL,
  headers: {
    'Content-Type': 'application/json',
    'Tenant-Id': process.env.NOVA_TENANT_ID!,
    'Authorization': process.env.NOVA_ACCESS_KEY!,
  },
})

const userQueues = new Map<string, Promise<void>>()

function splitMessage(text: string, maxLength = 4096): string[] {
  if (text.length <= maxLength) return [text]
  const parts: string[] = []
  let remaining = text
  while (remaining.length > 0) {
    if (remaining.length <= maxLength) {
      parts.push(remaining)
      break
    }
    let splitIndex = remaining.lastIndexOf('\n', maxLength)
    if (splitIndex <= 0) {
      splitIndex = maxLength
    }
    parts.push(remaining.slice(0, splitIndex))
    remaining = remaining.slice(splitIndex).trimStart()
  }
  return parts
}

async function getOrCreateConversation(telegramUserId: string, name: string): Promise<string> {
  const existing = getConversationId(telegramUserId)
  if (existing) return existing

  const agentId = getDefaultAgentId()

  const res = await oapiClient.post<{ conversation_id: string }>(
    '/v1/oapi/super_agent/chat/create_conversation',
    {
      agent_id: agentId,
      title: `Telegram User ${name || telegramUserId}`,
    },
  )

  const conversationId = res.conversation_id
  setConversationId(telegramUserId, conversationId, name)
  return conversationId
}

async function processMessage(
  ctx: Context,
  botToken: string,
  onMessage?: () => void,
): Promise<void> {
  const message = ctx.message
  if (!message) return

  const userId = String(message.from?.id ?? '')
  const userName = message.from?.username || message.from?.first_name || userId

  // Extract text
  const text = (message.text || message.caption || '').trim()

  // Extract attachments
  const attachments: BotAttachment[] = []

  // Handle photos - take the last one (largest size)
  if (message.photo && message.photo.length > 0) {
    const largestPhoto = message.photo[message.photo.length - 1]
    try {
      const file = await ctx.api.getFile(largestPhoto.file_id)
      if (file.file_path) {
        const downloadUrl = `https://api.telegram.org/file/bot${botToken}/${file.file_path}`
        attachments.push({
          url: downloadUrl,
          fileName: `telegram_photo_${Date.now()}.jpg`,
          mimeType: 'image/jpeg',
          size: largestPhoto.file_size,
        })
      }
    } catch (err) {
      console.error('[Telegram Bot] 获取图片文件失败:', err)
    }
  }

  // Handle documents
  if (message.document) {
    try {
      const file = await ctx.api.getFile(message.document.file_id)
      if (file.file_path) {
        const downloadUrl = `https://api.telegram.org/file/bot${botToken}/${file.file_path}`
        attachments.push({
          url: downloadUrl,
          fileName: message.document.file_name || `telegram_file_${Date.now()}`,
          mimeType: message.document.mime_type ?? undefined,
          size: message.document.file_size,
        })
      }
    } catch (err) {
      console.error('[Telegram Bot] 获取文档文件失败:', err)
    }
  }

  if (!text && attachments.length === 0) return

  BotLogger.log({
    platform: 'telegram',
    eventType: 'message_received',
    severity: 'info',
    message: `收到来自用户 ${userName} 的消息 (${attachments.length} 附件)`,
    details: { userId, chatId: String(message.chat.id) },
  })

  try {
    // Send typing action
    await ctx.api.sendChatAction(message.chat.id, 'typing').catch(() => {})
    const typingInterval = setInterval(() => {
      ctx.api.sendChatAction(message.chat.id, 'typing').catch(() => {})
    }, 5000)

    try {
      // Upload attachments if any
      let uploadFileIds: string[] | undefined
      if (attachments.length > 0) {
        uploadFileIds = await uploadBotAttachments(attachments)
        if (uploadFileIds.length === 0) uploadFileIds = undefined
      }

      const conversationId = await getOrCreateConversation(userId, userName)
      const response = await sendMessageAndWaitResponse(
        `telegram:${userId}`,
        conversationId,
        text || '',
        uploadFileIds,
      )

      if (!response) {
        await ctx.reply('没有收到回复，请稍后重试。')
        return
      }

      // Check for Markdown image syntax in response
      const imageRegex = /!\[([^\]]*)\]\(([^)]+)\)/g
      const images: Array<{ alt: string; url: string }> = []
      let match: RegExpExecArray | null

      while ((match = imageRegex.exec(response)) !== null) {
        images.push({ alt: match[1], url: match[2] })
      }

      if (images.length > 0) {
        // Remove image markdown from text
        const textWithoutImages = response.replace(imageRegex, '').trim()

        // Send images with caption
        for (let i = 0; i < images.length; i++) {
          const image = images[i]
          try {
            if (i === 0 && textWithoutImages) {
              // First image with caption (Telegram caption limit: 1024 chars)
              if (textWithoutImages.length <= 1024) {
                await ctx.replyWithPhoto(image.url, {
                  caption: textWithoutImages,
                  parse_mode: 'HTML',
                })
              } else {
                // Caption too long - send photo first, then text separately
                await ctx.replyWithPhoto(image.url)
                const textParts = splitMessage(textWithoutImages)
                for (const part of textParts) {
                  await ctx.reply(part)
                }
              }
            } else {
              await ctx.replyWithPhoto(image.url)
            }
          } catch {
            // If photo sending fails, send as link
            await ctx.reply(`${image.alt || '图片'}: ${image.url}`)
          }
        }

        // If no caption was sent with the first image and there's text
        if (images.length > 0 && textWithoutImages && textWithoutImages.length > 1024) {
          // Already handled above
        }
      } else {
        // Plain text response
        const parts = splitMessage(response)
        for (const part of parts) {
          await ctx.reply(part)
        }
      }

      if (onMessage) onMessage()

      BotLogger.log({
        platform: 'telegram',
        eventType: 'message_sent',
        severity: 'info',
        message: `已回复用户 ${userName}`,
      })
    } finally {
      clearInterval(typingInterval)
    }
  } catch (error) {
    const errMsg = error instanceof Error ? error.message : '未知错误'
    console.error('[Telegram Bot] 处理消息失败:', errMsg)
    await ctx.reply(`处理消息时出错: ${errMsg}`).catch(() => {})
    BotLogger.log({
      platform: 'telegram',
      eventType: 'error',
      severity: 'error',
      message: `处理消息失败: ${errMsg}`,
      details: { userId },
    })
  }
}

export function registerHandlers(bot: Bot, botToken: string, onMessage?: () => void): void {
  const handleMessage = (ctx: Context) => {
    const userId = String(ctx.message?.from?.id ?? '')
    if (!userId) return

    // Filter bot's own messages
    if (ctx.message?.from?.is_bot) return

    const currentQueue = userQueues.get(userId) ?? Promise.resolve()
    const newQueue = currentQueue.then(() => processMessage(ctx, botToken, onMessage))
    userQueues.set(userId, newQueue)

    newQueue.finally(() => {
      if (userQueues.get(userId) === newQueue) {
        userQueues.delete(userId)
      }
    })
  }

  bot.on('message:text', handleMessage)
  bot.on('message:photo', handleMessage)
  bot.on('message:document', handleMessage)
}
