const BASE_URL = process.env.LANGGRAPH_URL || "http://192.168.0.100:2026";
const ASSISTANT_ID = process.env.ASSISTANT_ID || "student_score";
const QUESTION = process.env.QUESTION || "白若耶最近10次数学考试的成绩趋势怎么样";

const CONTEXT = {
  team_id: process.env.TEAM_ID || "19",
  env: process.env.AGENT_ENV || "dev",
};

function parseJson(text) {
  try {
    return JSON.parse(text);
  } catch {
    return text;
  }
}

async function createThread() {
  const response = await fetch(`${BASE_URL}/threads`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({}),
  });

  if (!response.ok) {
    throw new Error(`create thread failed: ${response.status} ${await response.text()}`);
  }

  const thread = await response.json();
  return thread.thread_id;
}

function pickFinalAnswer(data) {
  if (!data || typeof data !== "object" || Array.isArray(data)) {
    return "";
  }

  const renderAnswer = data.render_answer;
  if (renderAnswer && typeof renderAnswer.answer === "string") {
    return renderAnswer.answer;
  }

  if (typeof data.answer === "string") {
    return data.answer;
  }

  return "";
}

function pickReasoning(data) {
  if (!data || typeof data !== "object" || Array.isArray(data)) {
    return "";
  }

  const renderAnswer = data.render_answer;
  if (renderAnswer && typeof renderAnswer.reasoning === "string") {
    return renderAnswer.reasoning;
  }

  if (typeof data.reasoning === "string") {
    return data.reasoning;
  }

  return "";
}

function handleEvent(eventName, dataText, answerParts, finalAnswers) {
  const data = parseJson(dataText);

  if (eventName === "updates") {
    const finalAnswer = pickFinalAnswer(data);
    const reasoning = pickReasoning(data);
    if (data && typeof data === "object" && !Array.isArray(data)) {
      console.log(`\n[updates] ${Object.keys(data).join(", ")}`);
    } else {
      console.log("\n[updates]", data);
    }
    if (reasoning) {
      console.log("\n[reasoning]");
      console.log(reasoning);
    }
    if (finalAnswer) {
      finalAnswers.push(finalAnswer);
      console.log("\n[final.answer]");
      console.log(finalAnswer);
    }
    return;
  }

  if (eventName === "messages") {
    const messageChunk = Array.isArray(data) ? data[0] : undefined;
    const content = messageChunk && typeof messageChunk.content === "string" ? messageChunk.content : "";
    if (content) {
      answerParts.push(content);
      process.stdout.write(content);
    }
    return;
  }

  if (eventName) {
    console.log(`\n[${eventName}]`, data);
  }
}

async function readSse(response) {
  if (!response.body) {
    throw new Error("response body is empty");
  }

  const reader = response.body.getReader();
  const decoder = new TextDecoder("utf-8");
  const answerParts = [];
  const finalAnswers = [];
  let buffer = "";

  while (true) {
    const { value, done } = await reader.read();
    if (done) break;

    buffer += decoder.decode(value, { stream: true });
    const events = buffer.split(/\r?\n\r?\n/);
    buffer = events.pop() || "";

    for (const rawEvent of events) {
      let eventName = "";
      const dataLines = [];

      for (const line of rawEvent.split(/\r?\n/)) {
        if (line.startsWith("event:")) {
          eventName = line.slice("event:".length).trim();
        } else if (line.startsWith("data:")) {
          dataLines.push(line.slice("data:".length).trimStart());
        }
      }

      handleEvent(eventName, dataLines.join("\n"), answerParts, finalAnswers);
    }
  }

  if (buffer.trim()) {
    handleEvent("", buffer.trim(), answerParts, finalAnswers);
  }

  return finalAnswers.at(-1) || answerParts.join("");
}

async function main() {
  const threadId = await createThread();
  const endpoint = `${BASE_URL}/threads/${threadId}/runs/stream`;
  const started = Date.now();

  console.log("=== LangGraph fetch stream test ===");
  console.log(`base_url: ${BASE_URL}`);
  console.log(`assistant_id: ${ASSISTANT_ID}`);
  console.log(`thread_id: ${threadId}`);
  console.log("");

  const response = await fetch(endpoint, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Accept: "text/event-stream",
    },
    body: JSON.stringify({
      assistant_id: ASSISTANT_ID,
      input: { question: QUESTION },
      context: CONTEXT,
      stream_mode: ["updates", "messages-tuple"],
    }),
  });

  if (!response.ok) {
    throw new Error(`stream request failed: ${response.status} ${await response.text()}`);
  }

  const answer = await readSse(response);
  const elapsed = ((Date.now() - started) / 1000).toFixed(2);
  console.log(`\n\n=== done: ${elapsed}s, answer length: ${answer.length} ===`);
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
