#!/usr/bin/env node
import {
  assignRoleColors,
  renderHubBanner,
  renderHubEvent
} from "./chunk-OJL3PY36.js";
import {
  DiscussionOrchestrator,
  getPreset,
  listPresets,
  resolveRoleProviders
} from "./chunk-Q3ZUDA6S.js";
import "./chunk-NZ4X6GUC.js";
import "./chunk-PDX44BCA.js";

// src/hub/index.ts
import { readFileSync, existsSync } from "fs";
import chalk from "chalk";
async function startHub(options, configManager, providers) {
  if (options.listPresets) {
    console.log("\n  Available discussion presets:\n");
    for (const p of listPresets()) {
      console.log(`    ${p.id.padEnd(16)} ${p.name}`);
      console.log(`    ${"".padEnd(16)} ${p.description}`);
      for (const r of p.roles) {
        console.log(`    ${"".padEnd(18)} \u2022 ${r.name} (${r.id})`);
      }
      console.log();
    }
    return;
  }
  let roles;
  let presetUsed;
  if (options.rolesFile) {
    if (!existsSync(options.rolesFile)) {
      console.error(`  \u2717 Roles file not found: ${options.rolesFile}`);
      process.exit(1);
    }
    try {
      const raw = readFileSync(options.rolesFile, "utf-8");
      const parsed = JSON.parse(raw);
      const rawRoles = Array.isArray(parsed) ? parsed : parsed.roles;
      if (!Array.isArray(rawRoles) || rawRoles.length === 0) {
        throw new Error("roles must be a non-empty array");
      }
      roles = rawRoles.map((r) => ({
        id: r.id ?? r.name?.toLowerCase().replace(/\s+/g, "-") ?? "agent",
        name: r.name ?? r.id ?? "Agent",
        persona: r.persona ?? r.description ?? `You are ${r.name ?? "an AI assistant"}.`,
        ...r.provider && { provider: r.provider },
        ...r.model && { model: r.model },
        ...r.color && { color: r.color }
      }));
    } catch (err) {
      console.error(`  \u2717 Invalid roles file: ${err.message}`);
      process.exit(1);
    }
  } else {
    const presetId = options.preset ?? "tech-review";
    presetUsed = getPreset(presetId);
    if (!presetUsed) {
      console.error(`  \u2717 Preset "${presetId}" not found. Use --presets to list available presets.`);
      process.exit(1);
    }
    roles = presetUsed.roles;
  }
  const defaultProvider = options.provider ?? configManager.get("defaultProvider");
  const allDefaultModels = configManager.get("defaultModels");
  let 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. Run \`aicli config\` first.`);
      process.exit(1);
    }
  }
  if (!providers.has(defaultProvider)) {
    console.error(`  \u2717 Provider "${defaultProvider}" not available. Check API key configuration.`);
    process.exit(1);
  }
  if (!options.topic?.trim()) {
    console.error("  \u2717 Please provide a discussion topic.");
    console.error('  Usage: aicli hub "your topic here"');
    console.error('         aicli hub --preset brainstorm "your topic here"');
    process.exit(1);
  }
  let context;
  const contextFileNames = [];
  if (options.contextFiles && options.contextFiles.length > 0) {
    const parts = [];
    for (const filePath of options.contextFiles) {
      if (!existsSync(filePath)) {
        console.error(`  \u2717 Context file not found: ${filePath}`);
        process.exit(1);
      }
      const content = readFileSync(filePath, "utf-8");
      const fileName = filePath.replace(/\\/g, "/").split("/").pop() ?? filePath;
      contextFileNames.push(fileName);
      parts.push(`### ${fileName}

${content}`);
    }
    context = parts.join("\n\n---\n\n");
  }
  {
    const resolution = resolveRoleProviders(
      roles,
      {
        has: (id) => providers.has(id),
        defaultModelFor: (id) => providers.has(id) ? providers.get(id).info.defaultModel : void 0
      },
      defaultProvider,
      defaultModel,
      providers.listAvailable().map((p) => p.info.id),
      options.mix
    );
    roles = resolution.roles;
    for (const w of resolution.warnings) console.error(chalk.yellow(`  \u26A0 ${w}`));
  }
  const mode = options.mode ?? "discuss";
  const config = {
    mode,
    roles,
    defaultProvider,
    defaultModel,
    maxRounds: options.maxRounds ?? (mode === "task" ? 15 : 10),
    enableTools: mode === "task",
    maxToolRoundsPerTurn: mode === "task" ? options.taskRounds ?? 30 : void 0,
    context,
    contextFiles: contextFileNames.length > 0 ? contextFileNames : void 0,
    humanSteer: options.steer === true,
    voteConverge: options.vote === true
  };
  if (mode === "discuss") {
    if (options.distributed) {
      await runDistributedDiscussion(config, providers, options.topic, options.port ?? 9527);
    } else {
      const state = await runDiscussion(config, providers, options.topic);
      if (options.save !== false && state.messages.length > 0) {
        try {
          const { persistDiscussion } = await import("./persist-A3R2IAYU.js");
          const { path } = await persistDiscussion(state, configManager, defaultProvider, defaultModel);
          console.log(chalk.dim(`
  \u{1F4BE} Saved to history \u2014 open it in the Web UI and hit \u{1F3AC} to replay.
     ${path}`));
        } catch (err) {
          console.error(chalk.yellow(`  \u26A0 Could not save discussion: ${err.message}`));
        }
      }
    }
  } else if (mode === "task") {
    await runTaskMode(config, providers, configManager, options.topic);
  }
}
async function runTaskMode(config, providers, configManager, topic) {
  const { TaskOrchestrator } = await import("./task-orchestrator-DTX44RG2.js");
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
  let interrupted = false;
  const onSigint = () => {
    if (interrupted) {
      console.log("\n  Force exit.");
      process.exit(0);
    }
    interrupted = true;
    orchestrator.abort();
  };
  process.on("SIGINT", onSigint);
  console.log();
  console.log(chalk.bold.white("  \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
  console.log(chalk.bold.white("  \u2551") + chalk.bold.yellow("  \u{1F680} AI-CLI Multi-Agent Hub \u2014 Task Mode                     ") + chalk.bold.white("\u2551"));
  console.log(chalk.bold.white("  \u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"));
  console.log(chalk.bold.white("  \u2551") + chalk.dim(`  Goal: ${topic.slice(0, 52)}`.padEnd(62)) + chalk.bold.white("\u2551"));
  console.log(chalk.bold.white("  \u2551") + chalk.dim(`  Team: ${config.roles.map((r) => r.name).join(", ")}`.slice(0, 62).padEnd(62)) + chalk.bold.white("\u2551"));
  if (config.contextFiles && config.contextFiles.length > 0) {
    console.log(chalk.bold.white("  \u2551") + chalk.dim(`  Context: ${config.contextFiles.join(", ")}`.padEnd(62)) + chalk.bold.white("\u2551"));
  }
  console.log(chalk.bold.white("  \u2551") + chalk.dim(`  Rounds/task: up to ${config.maxToolRoundsPerTurn ?? 15}`.padEnd(62)) + chalk.bold.white("\u2551"));
  console.log(chalk.bold.white("  \u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"));
  console.log(chalk.bold.white("  \u2551") + chalk.dim("  Plan \u2192 Approve \u2192 Execute \u2192 Review".padEnd(62)) + chalk.bold.white("\u2551"));
  console.log(chalk.bold.white("  \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
  console.log();
  try {
    await orchestrator.run(topic);
  } catch (err) {
    console.error(chalk.red(`
  \u2717 Task mode error: ${err.message}`));
  } finally {
    process.removeListener("SIGINT", onSigint);
  }
}
async function runDistributedDiscussion(config, providers, topic, port) {
  const { HubServer } = await import("./hub-server-GSTG5MNE.js");
  const hub = new HubServer(config, providers, port);
  let interrupted = false;
  const onSigint = () => {
    if (interrupted) {
      console.log("\n  Force exit.");
      hub.shutdown();
      process.exit(0);
    }
    interrupted = true;
    hub.abort();
  };
  process.on("SIGINT", onSigint);
  try {
    await hub.start(topic);
  } catch (err) {
    console.error(`
  \u2717 Hub error: ${err.message}`);
  } finally {
    process.removeListener("SIGINT", onSigint);
  }
}
async function runDiscussion(config, providers, topic) {
  assignRoleColors(config.roles);
  const orchestrator = new DiscussionOrchestrator(config, providers);
  orchestrator.onEvent = renderHubEvent;
  if (config.humanSteer) {
    const { createInterface } = await import("readline");
    orchestrator.onRoundReview = async ({ round, maxRounds }) => {
      const rl = createInterface({ input: process.stdin, output: process.stdout });
      const answer = await new Promise((resolve) => {
        rl.question(
          chalk.cyan(`
  \u{1F9ED} Round ${round}/${maxRounds} done. Steer next round? `) + chalk.dim("[Enter=continue \xB7 type guidance \xB7 /stop=end] "),
          resolve
        );
      });
      rl.close();
      const t = answer.trim();
      if (t === "/stop" || t.toLowerCase() === "stop") return { action: "stop" };
      return { action: "continue", message: t || void 0 };
    };
  }
  let interrupted = false;
  const onSigint = () => {
    if (interrupted) {
      console.log("\n  Force exit.");
      process.exit(0);
    }
    interrupted = true;
    orchestrator.abort();
  };
  process.on("SIGINT", onSigint);
  renderHubBanner(topic, config.roles, config.maxRounds ?? 10, config.contextFiles);
  try {
    return await orchestrator.run(topic);
  } catch (err) {
    console.error(`
  \u2717 Hub error: ${err.message}`);
    return orchestrator.getState();
  } finally {
    process.removeListener("SIGINT", onSigint);
  }
}
export {
  startHub
};
