import { v4 as uuid4 } from "uuid";

// 模板字符串装饰器
// @See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
export function template(strings, ...keys) {
  return (...values) => {
    const dict = values[values.length - 1] || {};
    const result = [strings[0]];
    keys.forEach((key, i) => {
      const value = Number.isInteger(key) ? values[key] : dict[key];
      result.push(value, strings[i + 1]);
    });
    return result.join("");
  };
}

export function getChatResponse({
  text,
  assistantId,
  userId,
  sessionName,
  model = "gpt-4o",
}) {
  if (!sessionName) {
    sessionName = uuid4();
  }
  const data = {
    assistant_id: assistantId,
    userId,
    message: text,
    session_name: sessionName,
    model,
  };
  const uid = uuid4();
  const ctrl = new AbortController();
  async function* generator() {
    const queue = [];
    let resolveQueuePromise: (value?: unknown) => void;
    let queuePromise = new Promise(
      (resolve) => (resolveQueuePromise = resolve)
    );
    let done = false;
    let error;
    let timer;

    // 创建 EventSource 实例
    const eventSource = new EventSource(
      `${process.env.NEXT_PUBLIC_GPT_BASE_URL}/question/${uid}`
    );

    // 处理消息事件
    eventSource.onmessage = (ev) => {
      const content = JSON.parse(ev.data)?.content;
      if (content === "[DONE]") {
        done = true;
        resolveQueuePromise?.();
        eventSource.close(); // 关闭连接
        return;
      }
      queue.push(content);
      resolveQueuePromise();
      queuePromise = new Promise((resolve) => (resolveQueuePromise = resolve));
    };

    // 处理错误事件
    eventSource.onerror = () => {
      done = true;
      resolveQueuePromise();
      eventSource.close(); // 关闭连接
    };

    ctrl.signal.addEventListener("abort", () => {
      done = true;
      resolveQueuePromise();
      eventSource.close();
    });
    fetch(
      `${process.env.NEXT_PUBLIC_GPT_BASE_URL}/ai_agent_park_chat_new`,
      {
        method: "POST",
        body: JSON.stringify({ ...data, uid }),
        headers: {
          "Content-Type": "application/json",
        },
      }
    );

    while (!done || queue.length > 0) {
      if (error) {
        throw error;
      }
      clearTimeout(timer);
      timer = setTimeout(() => {
        ctrl.abort();
        error = new Error("SSE timeout aborted.");
        resolveQueuePromise();
      }, 30000);
      if (queue.length > 0) {
        yield queue.shift();
      } else {
        await queuePromise;
      }
    }
    clearTimeout(timer);
  }
  return [generator(), ctrl];
}
