import { DataModel } from "@imengyu/js-request-transform";
import { RestfulApi } from "../restful";
import AgentApi from "./Agent";

export class AgentWorkApi extends RestfulApi<DataModel> {
  constructor() {
    super("content/agent", DataModel);
  }

  private static readonly WORK_MINI_MODEL_NAME = 'hunyuan-2.0-instruct-20251111';

  private static readonly QUESTION_RELATED_CACHE_TTL_MS = 5 * 60 * 1000;
  private static readonly QUESTION_RELATED_CACHE_MAX_SIZE = 200;
  private questionRelatedCache = new Map<string, { value: boolean; expireAt: number }>();

  private extractJsonObject<T>(content: string, fallback: T): T {
    try {
      return JSON.parse(content) as T;
    } catch {
      const start = content.indexOf('{');
      const end = content.lastIndexOf('}');
      if (start >= 0 && end > start) {
        try {
          return JSON.parse(content.slice(start, end + 1)) as T;
        } catch {
          return fallback;
        }
      }
      return fallback;
    }
  }

  private getQuestionRelatedCacheKey(thisQuestion: string, prevQuestions: string[], prevAnswers: string[]) {
    const normalize = (text: string) => text.trim().replace(/\s+/g, " ").slice(0, 240);
    return JSON.stringify({
      q: normalize(thisQuestion),
      prevQ: prevQuestions.map(normalize),
      prevA: prevAnswers.map(normalize),
    });
  }
  private getQuestionRelatedFromCache(cacheKey: string): boolean | undefined {
    const hit = this.questionRelatedCache.get(cacheKey);
    if (!hit)
      return undefined;
    if (Date.now() > hit.expireAt) {
      this.questionRelatedCache.delete(cacheKey);
      return undefined;
    }
    return hit.value;
  }
  private setQuestionRelatedCache(cacheKey: string, value: boolean) {
    const now = Date.now();
    this.questionRelatedCache.set(cacheKey, {
      value,
      expireAt: now + AgentWorkApi.QUESTION_RELATED_CACHE_TTL_MS,
    });
    if (this.questionRelatedCache.size <= AgentWorkApi.QUESTION_RELATED_CACHE_MAX_SIZE)
      return;

    for (const [key, item] of this.questionRelatedCache.entries()) {
      if (item.expireAt <= now)
        this.questionRelatedCache.delete(key);
    }
    while (this.questionRelatedCache.size > AgentWorkApi.QUESTION_RELATED_CACHE_MAX_SIZE) {
      const oldestKey = this.questionRelatedCache.keys().next().value as string | undefined;
      if (!oldestKey)
        break;
      this.questionRelatedCache.delete(oldestKey);
    }
  }


  /**
   * 调用模型，获取用户问题的一个简要概览
   * @param question 
   * @returns 简要概览，如果获取失败，则返回用户问题的前24个字符
   */
  async getQuestionOverview(question: string) {
    try {
      const result = await AgentApi.chat({
        model: AgentWorkApi.WORK_MINI_MODEL_NAME,
        messages: [
          { role: "system", content: `你是一个专业的概览生成器，请根据用户的问题生成一个简要概览，
            注意，你只对用户输入进行简要概括，不要回答问题。输出语言与用户输入语言一致。
            30字以内，输出格式为 JSON，结构为 { "overview": "简要概览" }
            示例：
            用户输入：我想学习如何使用Excel进行数据分析，请帮帮我，最好有详细的步骤说明
            模型输出：{ "overview": "如何使用Excel进行数据分析" }
            ` },
          { role: "user", content: question.slice(0, 240) },
        ],
      });
      const content = result.requireData().choices[0].message.content;
      const overview = this.extractJsonObject<{ overview: string }>(content ?? '{}', { overview: '' }).overview;
      return overview || question.slice(0, 24);
    } catch (error) {
      return question.slice(0, 24);
    }
  }

  /**
   * 获取用户内容的标题
   * @param userContent 用户内容
   * @returns 标题
   */
  async getTitle(userContent: string) {
    try {
      const result = await AgentApi.chat({
        model: AgentWorkApi.WORK_MINI_MODEL_NAME,
        messages: [
          { role: "system", content: `你是一个专业的标题生成器，请根据内容概括一个标题，
            输出格式为 JSON，结构为 { "title": "标题" }`
          },
          { role: "user", content: userContent.slice(0, 240) },
        ],
      });
      const content = result.requireData().choices[0].message.content;
      const title = (this.extractJsonObject<{ title: string }>(content ?? '{}', { title: '' })).title;
      return title || userContent.slice(0, 24);
    } catch (error) {
      console.error(error);
      return userContent.slice(0, 24);
    }
  }

  /**
   * 自动生成可能的问题
   * @param question 
   * @returns 可能的问题
   */
  async autoGeneratePossibleQuestions(question: string, aiAnswer: string) {
    try {
      const result = await AgentApi.chat({
        model: AgentWorkApi.WORK_MINI_MODEL_NAME,
        messages: [
          { role: "system", content: `你是一个专业的问题联想生成器，请根据用户的问题和AI回答生成2~4个用户可能感兴趣的问题，
            输出格式为 JSON，结构为 ["可能的问题1", "可能的问题2", "可能的问题3"]
            示例：
            用户输入：占道经营是什么
            AI回答：占道经营是指在未获得合法审批的情况下，占用城市道路、桥梁、广场等公共场所进行营利性买卖商品或提供服务的行为。这是一个复杂的社会现象，既关乎城市的“面子”——市容与秩序，也关乎民生的“里子”——生计与便利。
            模型输出：["有哪些城市成功治理占道经营的案例", "占道经营治理中有哪些常见执法难点", "如何平衡占道经营与城市交通秩序"]
            ` },
          { role: "user", content: question.slice(0, 1000) },
          { role: "assistant", content: aiAnswer.slice(0, 1000) },
        ],
      });
      const content = result.requireData().choices[0].message.content;
      return (JSON.parse(content ?? '[]') as string[]);
    } catch (error) {
      return [];
    }
  }

  /**
   * 检查问题是否相关
   * @param thisQuestion 
   * @param prevQuestions 
   * @param prevAnswers 
   */
  async checkQuestionRelated(thisQuestion: string, prevQuestions: string[], prevAnswers: string[]) {
    const currentQuestion = thisQuestion.trim();
    if (!currentQuestion)
      return false;
    if ((prevQuestions?.length || 0) === 0 && (prevAnswers?.length || 0) === 0)
      return false;
    const cacheKey = this.getQuestionRelatedCacheKey(currentQuestion, prevQuestions, prevAnswers);
    const cached = this.getQuestionRelatedFromCache(cacheKey);
    if (typeof cached === "boolean")
      return cached;

    try {
      const historyPairs = Array.from({
        length: Math.max(prevQuestions.length, prevAnswers.length),
      }).map((_, index) => ({
        q: prevQuestions[index]?.slice(0, 500) || '',
        a: prevAnswers[index]?.slice(0, 500) || '',
      }));
      const result = await AgentApi.chat({
        model: AgentWorkApi.WORK_MINI_MODEL_NAME,
        messages: [
          {
            role: "system",
            content: `你是一个对话相关性分类器。请根据“当前问题”和“历史问答”判断是否相关。
返回 JSON：{ "related": true|false, "confidence": 0~1, "reason": "简短原因" }。
判定标准：
1) 主题、实体、任务目标连续，算 related=true；
2) 完全换话题、换任务目标，算 related=false；
3) 不确定时倾向 false。`,
          },
          {
            role: "user",
            content: JSON.stringify({
              currentQuestion,
              history: historyPairs,
            }),
          },
        ],
      });

      const content = result.requireData().choices[0].message.content || "{}";
      const parsed = this.extractJsonObject<{ related?: boolean; confidence?: number }>(content, 
        { related: false, confidence: 0 }
      );
      const finalRelated =
        typeof parsed.related === "boolean"
          ? parsed.related
          : (typeof parsed.confidence === "number" ? parsed.confidence >= 0.65 : false);
      this.setQuestionRelatedCache(cacheKey, finalRelated);
      return finalRelated;
    } catch (error) {
      this.setQuestionRelatedCache(cacheKey, false);
      return false;
    }
  }

  /**
   * 生成会话阶段摘要（中期记忆）
   */
  async summarizeConversationStage(historyLines: string[], prevSummary = ""): Promise<string> {
    const historyText = historyLines.map((line) => line.trim()).filter(Boolean).join("\n");
    if (!historyText)
      return prevSummary;
    try {
      const result = await AgentApi.chat({
        model: AgentWorkApi.WORK_MINI_MODEL_NAME,
        messages: [
          {
            role: "system",
            content: `你是会话记忆压缩器。请将“历史对话”压缩为可供后续对话参考的中期摘要。
要求：
1) 保留关键目标、结论、约束、未完成事项；
2) 删除寒暄与重复信息；
3) 摘要尽量精炼（建议 8~12 条）；
4) 返回 JSON：{ "summary": "多行文本" }。`,
          },
          {
            role: "user",
            content: JSON.stringify({
              previousSummary: prevSummary || "",
              historyText,
            }),
          },
        ],
      });
      const content = result.requireData().choices[0].message.content || "{}";
      const parsed = this.extractJsonObject<{ summary?: string }>(content, {});
      return (parsed.summary || prevSummary || "").trim();
    } catch {
      return prevSummary;
    }
  }

  /**
   * 抽取长期记忆（稳定偏好/身份/长期约束）
   */
  async extractLongTermMemory(historyLines: string[], existingLongMemory = "", maxItems = 12): Promise<string> {
    const historyText = historyLines.map((line) => line.trim()).filter(Boolean).join("\n");
    if (!historyText)
      return existingLongMemory;
    try {
      const result = await AgentApi.chat({
        model: AgentWorkApi.WORK_MINI_MODEL_NAME,
        messages: [
          {
            role: "system",
            content: `你是长期记忆抽取器。请从对话中抽取“长期稳定且值得记住”的信息：
- 用户身份/背景（稳定）
- 长期偏好、禁忌、风格要求
- 长期目标与硬约束
- 联系方式等高价值事实
不要输出瞬时任务细节。
返回 JSON：{ "items": ["记忆1", "记忆2"] }。
如无新增重要信息可返回空数组。`,
          },
          {
            role: "user",
            content: JSON.stringify({
              existingLongMemory,
              historyText,
              maxItems,
            }),
          },
        ],
      });
      const content = result.requireData().choices[0].message.content || "{}";
      const parsed = this.extractJsonObject<{ items?: string[] }>(content, {});
      const current = existingLongMemory
        .split("\n")
        .map((line) => line.trim().replace(/^- /, ""))
        .filter(Boolean);
      const merged = new Set<string>(current);
      for (const item of parsed.items || []) {
        const text = String(item || "").trim();
        if (text)
          merged.add(text);
      }
      return Array.from(merged)
        .slice(0, Math.max(1, maxItems))
        .map((item) => `- ${item}`)
        .join("\n");
    } catch {
      return existingLongMemory;
    }
  }
}

export default new AgentWorkApi();

