import { RespMessage } from "../../constant/message"
import { Context } from "../../types"
import { genContextManually } from "../../utils/genContext"
import llm from "../../utils/llm"
import { getTimeRange } from "../../utils/time"
import getChatHistory from "./chatHistory"

/**
 * 总结指定聊天记录
 * @param {Context} ctx - 请求上下文
 * @param {string} timeScope - 时间范围
 * @param {any} subscription - 订阅信息
 * @returns {Promise<void>}
 */
const genSummary = async (
  ctx: Context,
  timeScope: "daily" | "weekly",
  trigger: "auto" | "manual"
) => {
  const {
    db,
    logger,
    requestId,
    larkCard,
    larkService,
    appInfo,
    larkService: { message },
  } = ctx
  logger.info("生成摘要", { timeScope, trigger })
  const cardGender = larkCard.child("groupAgent")
  try {
    if (trigger === "manual") {
      await message.updateOrReply(
        cardGender.genPendingCard("总结中,请稍等...")
      )
    }
    // 获取群聊信息
    const chat = await db.chat.getByCtx(ctx)
    if (!chat) {
      throw new Error("Failed to get chat info")
    }
    const { chatId } = chat

    // 获取时间范围
    const { startTime, endTime } = getTimeRange(timeScope)

    // 计时开始
    const processStart = Date.now()

    // 获取聊天记录
    const { messages: chatHistory } = await getChatHistory(
      { larkService, logger } as Context,
      {
        chatId,
        startTime,
        endTime,
        excludeMentions: [appInfo.appName],
      }
    )

    if (chatHistory.length === 0) {
      if (trigger === "manual") {
        throw new Error("No message in chat")
      } else {
        logger.info(`No message in chat ${chatId}`)
        return
      }
    }

    // 使用大模型总结消息
    const llmRes = await llm.invoke(
      `${timeScope}Summary`,
      {
        chatHistory: JSON.stringify(chatHistory),
        time: new Date().toLocaleString("zh-CN", {
          timeZone: "Asia/Shanghai",
        }),
      },
      requestId
    )

    // 计时结束
    const processEnd = Date.now()
    const processingTime = ((processEnd - processStart) / 1000).toFixed(2)
    logger.info(
      `LLM takes time: ${processingTime}s, see detail: http://langfuse.ai.srv/project/cm1j2tkj9001gukrgdvc1swuw/sessions/${requestId}`
    )

    // 生成卡片内容
    const cardContent = cardGender.genCard("autoReport", {
      llmRes,
      timeScope: timeScope === "daily" ? "今日日报" : "本周周报",
    })

    // 发送卡片消息,手动触发时回复原消息
    if (trigger === "manual") {
      await message.updateOrReply(cardContent)
    } else {
      await larkService.message.sendCard2Chat(chatId, cardContent)
    }

    // 记录总结日志
    await db.grpSumLog.create({
      chat: chat.id,
      content: JSON.stringify(cardContent),
      langfuseLink: `http://langfuse.ai.srv/project/cm1j2tkj9001gukrgdvc1swuw/sessions/${requestId}`,
    })
  } catch (error: any) {
    logger.error(`Failed to summarize chat: ${error.message}`)
    const errorCard = cardGender.genErrorCard(
      `${RespMessage.summaryFailed}: ${error.message}`
    )
    // 手动触发时回复原消息
    if (trigger === "manual") {
      await message.updateOrReply(errorCard)
    }
    // 自动触发发送给自己的订阅群
    else {
      await larkService.message.sendCard2Chat(appInfo.errChatId, errorCard)
    }
  }
}

/**
 * 自动总结聊天记录
 * @returns {Promise<void>}
 */
const genAllReport = async (timeScope: "daily" | "weekly" = "daily") => {
  const ctx = await genContextManually()
  const { logger, db } = ctx
  logger.info("生成所有群聊总结", { timeScope })
  try {
    // 获取所有需要自动总结的群组
    const chatList = await db.chat.getNeedSummaryChats("all")
    logger.debug(`chatList: ${JSON.stringify(chatList)}`)
    if (!chatList || chatList.length === 0) {
      logger.info(`No chat need to summarize`)
      return
    }
    // 总结
    for (const chat of chatList) {
      const newCtx = await genContextManually()
      newCtx.larkBody.chatId = chat.chatId
      let scope = "daily" as "daily" | "weekly"
      if (timeScope === "weekly" && chat.weeklySummary) {
        scope = "weekly"
      }
      await genSummary(newCtx, scope, "auto")
    }
  } catch (e: any) {
    logger.error(`Auto summary error: ${e.message}`)
  }
}

/**
 * 立即生成日报或周报(测试用)
 * @param {Context} ctx - 请求上下文
 * @returns {Promise<void>}
 */
const gen4Test = async (ctx: Context, timeScope: "daily" | "weekly") => {
  const {
    logger,
    larkBody: { chatId },
  } = ctx
  try {
    logger.info("手动生成日报或者周报", { timeScope })
    // 总结
    await genSummary(ctx, timeScope, "manual")
  } catch (error: any) {
    logger.error(`Failed to summarize chat ${chatId}: ${error.message}`)
  }
}

/**
 * 设置订阅
 * @param {Context} ctx - 请求上下文
 * @param {string} timeScope - 订阅时间范围
 * @param {boolean} value - 订阅值
 * @returns {Promise<void>}
 */
const setSubscription = async (
  ctx: Context,
  timeScope: "daily" | "weekly",
  value: boolean
) => {
  const {
    db,
    larkService: { message },
    logger,
    larkBody,
    larkCard,
  } = ctx
  const cardGender = larkCard.child("groupAgent")
  const sendErrorMsg = (msg: string) =>
    message.updateOrReply(
      cardGender.genErrorCard(
        `${
          value ? RespMessage.registerFailed : RespMessage.cancelFailed
        }: ${msg}`
      )
    )
  try {
    const { chatId } = larkBody
    if (!chatId) {
      throw new Error("Invalid chatId")
    }
    // 获取群组信息
    const chat = await db.chat.getByCtx(ctx)
    if (!chat) {
      throw new Error("Failed to get chat info")
    }

    let hasUpdate = false
    // 更新订阅信息, 如果订阅信息没有变化则不更新
    if (chat[`${timeScope}Summary`] !== value) {
      logger.info("value is different, update subscription")
      const res = await db.chat.update(chat.id, {
        [`${timeScope}Summary`]: value,
      })
      if (!res) {
        throw new Error("Failed to update subscription")
      }
      hasUpdate = true
    }
    let msg = ""
    if (!hasUpdate && value) {
      msg =
        timeScope === "daily"
          ? RespMessage.hasRegisteredDaily
          : RespMessage.hasRegisteredWeekly
    } else if (!value) {
      msg =
        timeScope === "daily"
          ? RespMessage.cancelDailySuccess
          : RespMessage.cancelWeeklySuccess
    } else {
      msg =
        timeScope === "daily"
          ? RespMessage.registerDailySuccess
          : RespMessage.registerWeeklySuccess
    }
    // 发送成功消息
    await message.updateOrReply(cardGender.genSuccessCard(msg))
  } catch (e: any) {
    logger.error(`Subscribe error: ${e.message}`)
    await sendErrorMsg(e.message)
  }
}

const report = {
  genSummary,
  genAllReport,
  gen4Test,
  setSubscription,
}

export default report