import type { InnerContextManager, ContextMemoryConfig, RoundedMessages } from "../Context";
import AgentWorkApi from "@/api/agent/AgentWorks";

export async function useSlideWindowMemoryStrategy(options: {
  roundedMessages: RoundedMessages[];
  contextMemoryConfig: Required<ContextMemoryConfig>,
  maxTokens: number,
  contextManager: InnerContextManager,
}): Promise<RoundedMessages[]> {

  const {
    roundedMessages,
    maxTokens,
    contextManager,
  } = options;
  const {
    slideWindowShortRelatedLookback,
    slideWindowShortUnrelatedLookback,
    slideWindowWindowMinRounds,
    slideWindowWindowMaxRounds,
    slideWindowHeadRounds,
    slideWindowTailRounds,
  } = options.contextMemoryConfig || {};

  //如果消息列表token数量小于预算，则直接返回消息列表
  if (contextManager.estimateRoundedMessagesTokens(roundedMessages) <= maxTokens)
    return roundedMessages;

  const totalRounds = roundedMessages.length;
  const lastRounded = roundedMessages[totalRounds - 1];
  const currentQuestion = lastRounded?.userMessages?.[0]?.content || '';

  //检查当前问题与历史问题是否相关，若不相干，则按“短期/不记忆”处理
  const historyRounds = roundedMessages.slice(0, -1);
  const prevQuestions = historyRounds.map(r => r.userMessages?.[0]?.content || '').filter(Boolean);
  const prevAnswers = historyRounds.map(r => (r.aiMessages || []).map(m => m.content).filter(Boolean).join('\n')).filter(Boolean);
  const relatedLookback = Math.max(0, slideWindowShortRelatedLookback || 0);
  const isRelated = relatedLookback <= 0
    ? true
    : await AgentWorkApi.checkQuestionRelated(
      currentQuestion,
      prevQuestions.slice(-relatedLookback),
      prevAnswers.slice(-relatedLookback),
    );
  if (!isRelated) {
    const unrelatedLookback = Math.max(0, slideWindowShortUnrelatedLookback || 0);
    const keepRounds = Math.max(1, unrelatedLookback + 1);
    return roundedMessages.slice(-keepRounds);
  }

  //采用滑动窗口模式，收尾保留
  const headRounds = Math.max(0, slideWindowHeadRounds || 0);
  const tailRounds = Math.max(0, slideWindowTailRounds || 0);
  const minWindowRounds = Math.max(0, slideWindowWindowMinRounds || 0);
  const maxWindowRounds = Math.max(minWindowRounds, slideWindowWindowMaxRounds || 0);

  function buildCandidate(windowRounds: number): RoundedMessages[] {
    const len = roundedMessages.length;
    const safeHead = Math.min(headRounds, len);
    const safeTail = Math.min(tailRounds, Math.max(0, len - safeHead));

    const head = roundedMessages.slice(0, safeHead);
    const tail = safeTail > 0 ? roundedMessages.slice(len - safeTail) : [];

    // middle window is selected from the tail side (more recent first)
    const availableMiddleEnd = len - safeTail;
    const middleEnd = Math.max(safeHead, availableMiddleEnd);
    const desired = Math.min(Math.max(0, windowRounds), Math.max(0, middleEnd - safeHead));
    const middleStart = Math.max(safeHead, middleEnd - desired);
    const middle = roundedMessages.slice(middleStart, middleEnd);

    // de-duplicate by reference while keeping order
    const res: RoundedMessages[] = [];
    const seen = new Set<RoundedMessages>();
    for (const g of [...head, ...middle, ...tail]) {
      if (!seen.has(g)) {
        seen.add(g);
        res.push(g);
      }
    }
    return res;
  }

  // 先按 maxWindowRounds 选择，超预算则逐步收缩
  let windowRounds = Math.min(maxWindowRounds, totalRounds);
  let candidate = buildCandidate(windowRounds);
  while (windowRounds > minWindowRounds && contextManager.estimateRoundedMessagesTokens(candidate) > maxTokens) {
    windowRounds--;
    candidate = buildCandidate(windowRounds);
  }

  // 如果仍超预算，进一步从“中间/头部/尾部(最旧的尾部)”裁剪，确保至少保留最后一轮
  while (candidate.length > 1 && contextManager.estimateRoundedMessagesTokens(candidate) > maxTokens) {
    const len = candidate.length;
    const last = candidate[len - 1];

    // 优先裁掉更旧的中间段（避免伤害 tail）
    const base = buildCandidate(windowRounds);
    const headSet = new Set(base.slice(0, Math.min(headRounds, base.length)));
    const tailSet = new Set(tailRounds > 0 ? base.slice(-Math.min(tailRounds, base.length)) : []);

    let removeIndex = -1;
    for (let i = 0; i < len - 1; i++) {
      const g = candidate[i];
      if (headSet.has(g) || tailSet.has(g)) continue;
      removeIndex = i;
      break;
    }
    // 其次裁掉 head（从末端裁，尽量保留更“头”的指令/设定）
    if (removeIndex === -1) {
      for (let i = len - 2; i >= 0; i--) {
        const g = candidate[i];
        if (tailSet.has(g)) continue;
        removeIndex = i;
        break;
      }
    }

    if (removeIndex === -1) break;
    const next = candidate.slice(0, removeIndex).concat(candidate.slice(removeIndex + 1));
    candidate = next.length ? next : [last];
  }
  
  return candidate;
}
