#!/usr/bin/env node
import "./chunk-PDX44BCA.js";

// src/hub/agent-client.ts
import WebSocket from "ws";
import chalk from "chalk";
import { createInterface } from "readline";
var PASS_MARKER = "[PASS]";
async function joinHub(options, configManager, providers) {
  const host = options.host ?? "localhost";
  const url = `ws://${host}:${options.port}`;
  const isHuman = options.human === true;
  let defaultProvider = "";
  let defaultModel = "";
  if (!isHuman) {
    defaultProvider = options.provider ?? configManager.get("defaultProvider");
    const allDefaultModels = configManager.get("defaultModels");
    defaultModel = options.model ?? allDefaultModels[defaultProvider] ?? "";
    if (!defaultModel) {
      try {
        const p = providers.get(defaultProvider);
        defaultModel = p.info.defaultModel;
      } catch {
        console.error(`  \u2717 Provider "${defaultProvider}" not configured.`);
        process.exit(1);
      }
    }
  }
  let rl = null;
  if (isHuman) {
    rl = createInterface({ input: process.stdin, output: process.stdout });
  }
  console.log();
  console.log(chalk.bold.cyan(isHuman ? "  \u{1F464} AI-CLI Hub \u2014 Human Participant" : "  \u{1F916} AI-CLI Agent \u2014 Connecting to Hub"));
  console.log(chalk.dim(`  Server: ${url}`));
  if (options.role) console.log(chalk.dim(`  Requested role: ${options.role}`));
  if (isHuman) {
    console.log(chalk.dim("  Mode: HUMAN (you type your responses)"));
    console.log(chalk.dim("  Tip: type [PASS] to skip your turn, empty line to send"));
  } else {
    console.log(chalk.dim(`  Provider: ${defaultProvider} / ${defaultModel}`));
  }
  console.log();
  const ws = new WebSocket(url);
  let myRoleId = "";
  let myRoleName = "";
  let topic = "";
  let allRoles = [];
  let hubContext;
  let persona = "";
  ws.on("open", () => {
    console.log(chalk.green("  \u2713 Connected to Hub"));
    const msg = { type: "register", roleId: options.role ?? "" };
    ws.send(JSON.stringify(msg));
  });
  ws.on("close", () => {
    if (rl) rl.close();
    console.log(chalk.dim("\n  Disconnected from Hub."));
    process.exit(0);
  });
  ws.on("error", (err) => {
    console.error(chalk.red(`
  \u2717 Connection error: ${err.message}`));
    process.exit(1);
  });
  ws.on("message", async (raw) => {
    try {
      const msg = JSON.parse(raw.toString());
      await handleMessage(msg);
    } catch (err) {
      console.error(chalk.red(`  \u2717 Message error: ${err.message}`));
    }
  });
  async function handleMessage(msg) {
    switch (msg.type) {
      case "welcome":
        myRoleId = msg.roleId;
        myRoleName = msg.roleName;
        topic = msg.topic || topic;
        allRoles = msg.roles;
        hubContext = msg.context;
        persona = msg.persona || buildPersonaFromRole(myRoleId, myRoleName);
        console.log(chalk.bold(`  \u{1F4CB} Assigned role: ${chalk.cyan(myRoleName)} (${myRoleId})`));
        if (topic) {
          console.log(chalk.dim(`  Topic: ${topic}`));
        }
        console.log(chalk.dim(`  Participants: ${allRoles.map((r) => r.name).join(", ")}`));
        console.log(chalk.dim("  Waiting for discussion to start...\n"));
        break;
      case "round_start":
        console.log(chalk.dim(`  \u2500\u2500 Round ${msg.round}/${msg.maxRounds} ${"\u2500".repeat(40)}
`));
        break;
      case "your_turn": {
        let response;
        if (isHuman) {
          console.log(chalk.bold.green(`
  \u270F\uFE0F  Your turn to speak, ${myRoleName}! (Round ${msg.round}/${msg.maxRounds})`));
          console.log(chalk.dim("  Type your response (multi-line: end with empty line). [PASS] to skip.\n"));
          response = await readMultiLineInput(rl);
        } else {
          console.log(chalk.bold.cyan(`  \u{1F4AD} Your turn to speak (Round ${msg.round}/${msg.maxRounds})...`));
          try {
            response = await generateResponse(
              topic,
              msg.history,
              msg.round,
              msg.maxRounds,
              myRoleId,
              myRoleName,
              persona,
              providers,
              defaultProvider,
              defaultModel,
              hubContext
            );
          } catch (err) {
            console.error(chalk.red(`  \u2717 Response error: ${err.message}`));
            const errReply = { type: "error", message: err.message };
            ws.send(JSON.stringify(errReply));
            break;
          }
        }
        const passed = response.trim().toUpperCase() === PASS_MARKER || response.trim() === "";
        if (passed) {
          console.log(chalk.dim("  [PASS \u2014 nothing to add]\n"));
        } else if (!isHuman) {
          console.log(chalk.cyan(`  \u250C\u2500 ${myRoleName} (you)`));
          for (const line of response.split("\n")) {
            console.log(chalk.cyan("  \u2502 ") + line);
          }
          console.log(chalk.cyan("  \u2514" + "\u2500".repeat(50)));
          console.log();
        }
        const reply = {
          type: "response",
          content: passed ? "" : response.trim(),
          passed
        };
        ws.send(JSON.stringify(reply));
        break;
      }
      case "agent_spoke": {
        const m = msg.message;
        if (m.speaker === myRoleId) break;
        if (m.passed) {
          console.log(chalk.dim(`  ${m.speakerName}: [PASS]
`));
        } else {
          console.log(chalk.magenta(`  \u250C\u2500 ${m.speakerName} (${m.speaker})`));
          for (const line of m.content.split("\n")) {
            console.log(chalk.magenta("  \u2502 ") + line);
          }
          console.log(chalk.magenta("  \u2514" + "\u2500".repeat(50)));
          console.log();
        }
        break;
      }
      case "discussion_end":
        console.log();
        if (msg.reason === "consensus") {
          console.log(chalk.green.bold("  \u2713 Consensus reached \u2014 discussion ended."));
        } else if (msg.reason === "max_rounds") {
          console.log(chalk.yellow("  \u26A0 Maximum rounds reached \u2014 discussion ended."));
        } else {
          console.log(chalk.yellow("  \u26A0 Discussion interrupted by hub operator."));
        }
        if (msg.summary) {
          console.log();
          console.log(chalk.bold("  \u{1F4CB} Summary:"));
          for (const line of msg.summary.split("\n")) {
            console.log("  " + line);
          }
        }
        console.log();
        break;
      case "waiting":
        console.log(chalk.dim(`  ${msg.message}`));
        break;
      case "error":
        console.error(chalk.red(`  \u2717 Hub error: ${msg.message}`));
        break;
    }
  }
  await new Promise(() => {
  });
}
async function generateResponse(topic, history, round, maxRounds, roleId, roleName, persona, providers, providerId, modelId, context) {
  const provider = providers.get(providerId);
  if (!provider) throw new Error(`Provider "${providerId}" not available`);
  const contextSection = context ? `

## Reference Documents
${context}` : "";
  const systemPrompt = `# Multi-Agent Discussion \u2014 Role: ${roleName}

${persona}

## Discussion Rules
- You are participating in a multi-agent discussion about the topic below.
- You can see what other participants have said. Build on their ideas, challenge them, or add your own perspective.
- Stay in character as ${roleName}. Respond from your role's expertise and viewpoint.
- Keep responses concise and focused (2-6 paragraphs). Do not repeat what others have already said.
- If you have nothing meaningful to add (others have covered your points), respond with exactly: [PASS]
- This is round ${round} of ${maxRounds}. ${round >= maxRounds - 1 ? "This is one of the final rounds \u2014 try to converge on conclusions." : ""}
- Use the language that the topic is written in (if the topic is in Chinese, respond in Chinese).

## Topic
${topic}${contextSection}`;
  const messages = [];
  for (const msg of history) {
    if (msg.passed) continue;
    if (msg.speaker === roleId) {
      messages.push({ role: "assistant", content: msg.content, timestamp: new Date(msg.timestamp) });
    } else {
      messages.push({ role: "user", content: `[${msg.speakerName} (${msg.speaker})]:
${msg.content}`, timestamp: new Date(msg.timestamp) });
    }
  }
  if (messages.length === 0) {
    messages.push({ role: "user", content: "Please share your initial thoughts on the topic. You are the first to speak.", timestamp: /* @__PURE__ */ new Date() });
  } else {
    messages.push({ role: "user", content: "It is now your turn. Consider what others have said and share your perspective. If you have nothing to add, respond with [PASS].", timestamp: /* @__PURE__ */ new Date() });
  }
  const response = await provider.chat({
    messages,
    model: modelId,
    systemPrompt,
    stream: false,
    temperature: 0.7,
    maxTokens: 4096
  });
  return response.content.trim();
}
function buildPersonaFromRole(roleId, roleName) {
  return `You are ${roleName} (${roleId}). You are an expert in your domain.
Respond thoughtfully based on your area of expertise.
Be constructive, collaborative, and open to other perspectives while maintaining your professional viewpoint.`;
}
function readMultiLineInput(rl) {
  return new Promise((resolve) => {
    const lines = [];
    let lastLineEmpty = false;
    const prompt = () => {
      rl.question(chalk.green("  > "), (line) => {
        if (line === "" && lines.length > 0) {
          if (lastLineEmpty) {
            resolve(lines.join("\n"));
            return;
          }
          lastLineEmpty = true;
          lines.push("");
          prompt();
          return;
        }
        if (line === "" && lines.length === 0) {
          resolve(PASS_MARKER);
          return;
        }
        if (line.trim().toUpperCase() === PASS_MARKER && lines.length === 0) {
          resolve(PASS_MARKER);
          return;
        }
        lastLineEmpty = false;
        lines.push(line);
        prompt();
      });
    };
    prompt();
  });
}
export {
  joinHub
};
