// retoor <retoor@molodetz.nl>
import { initAgent } from "./agent.js";
import * as agents from "./agents/index.js";

export default class Application {
  constructor() {
    this.agents = agents;
    this.agent = null;
    this.name = null;
    this.assistant = null;
  }

  names() {
    return Object.keys(this.agents);
  }

  resolve(agent) {
    if (typeof agent !== "string") return agent;
    const match = this.names().find((name) => name.toLowerCase() === agent.toLowerCase());
    if (!match) throw new Error("Unknown md-clippy agent: " + agent);
    return this.agents[match];
  }

  async load(agent) {
    if (this.agent) this.dispose();
    const loader = this.resolve(agent);
    this.name = typeof agent === "string" ? agent : null;
    this.agent = await initAgent(loader);
    return this.agent;
  }

  async show(agent) {
    if (agent || !this.agent) await this.load(agent || this.names()[0]);
    this.agent.show();
    return this.agent;
  }

  speak(text, options) {
    if (!this.agent) throw new Error("No md-clippy agent loaded");
    this.agent.speak(text, options);
    return this.agent;
  }

  speakStream(source, options) {
    if (!this.agent) throw new Error("No md-clippy agent loaded");
    return this.agent.speakStream(source, options);
  }

  play(animation, timeout, callback) {
    if (!this.agent) throw new Error("No md-clippy agent loaded");
    return this.agent.play(animation, timeout, callback);
  }

  animate() {
    if (!this.agent) throw new Error("No md-clippy agent loaded");
    return this.agent.animate();
  }

  moveTo(x, y, duration) {
    if (!this.agent) throw new Error("No md-clippy agent loaded");
    this.agent.moveTo(x, y, duration);
    return this.agent;
  }

  hide(fast, callback) {
    if (!this.agent) return;
    this.agent.hide(fast, callback);
  }

  stop() {
    if (this.agent) this.agent.stop();
  }

  get aiEnabled() {
    return !!this.assistant;
  }

  async connectAI(config) {
    const { default: Assistant } = await import("./ai/assistant.js");
    this.assistant = new Assistant(this, config);
    return this.assistant;
  }

  disconnectAI() {
    this.assistant = null;
  }

  async ask(text) {
    if (!this.assistant) {
      throw new Error("AI is not connected. Call app.connectAI() first.");
    }
    return this.assistant.ask(text);
  }

  dispose() {
    if (this.agent) {
      this.agent.dispose();
      this.agent = null;
      this.name = null;
    }
  }
}
