import { tracked } from "@glimmer/tracking";
import { ajax } from "discourse/lib/ajax";
import RestModel from "discourse/models/rest";

const CREATE_ATTRIBUTES = [
  "id",
  "name",
  "description",
  "commands",
  "system_prompt",
  "allowed_group_ids",
  "enabled",
  "system",
  "priority",
  "top_p",
  "temperature",
  "user_id",
  "mentionable",
  "default_llm",
  "user",
  "max_context_posts",
  "vision_enabled",
  "vision_max_pixels",
  "rag_uploads",
  "rag_chunk_tokens",
  "rag_chunk_overlap_tokens",
  "rag_conversation_chunks",
  "question_consolidator_llm",
  "allow_chat",
];

const SYSTEM_ATTRIBUTES = [
  "id",
  "allowed_group_ids",
  "enabled",
  "system",
  "priority",
  "user_id",
  "mentionable",
  "default_llm",
  "user",
  "max_context_posts",
  "vision_enabled",
  "vision_max_pixels",
  "rag_uploads",
  "rag_chunk_tokens",
  "rag_chunk_overlap_tokens",
  "rag_conversation_chunks",
  "question_consolidator_llm",
  "allow_chat",
];

class CommandOption {
  @tracked value = null;
}

export default class AiPersona extends RestModel {
  // this code is here to convert the wire schema to easier to work with object
  // on the wire we pass in/out commands as an Array.
  // [[CommandName, {option1: value, option2: value}], CommandName2, CommandName3]
  // So we rework this into a "commands" property and nested commandOptions
  init(properties) {
    if (properties.commands) {
      properties.commands = properties.commands.map((command) => {
        if (typeof command === "string") {
          return command;
        } else {
          let [commandId, options] = command;
          for (let optionId in options) {
            if (!options.hasOwnProperty(optionId)) {
              continue;
            }
            this.getCommandOption(commandId, optionId).value =
              options[optionId];
          }
          return commandId;
        }
      });
    }
    super.init(properties);
    this.commands = properties.commands;
  }

  async createUser() {
    const result = await ajax(
      `/admin/plugins/discourse-ai/ai-personas/${this.id}/create-user.json`,
      {
        type: "POST",
      }
    );
    this.user = result.user;
    this.user_id = this.user.id;
    return this.user;
  }

  getCommandOption(commandId, optionId) {
    this.commandOptions ||= {};
    this.commandOptions[commandId] ||= {};
    return (this.commandOptions[commandId][optionId] ||= new CommandOption());
  }

  populateCommandOptions(attrs) {
    if (!attrs.commands) {
      return;
    }
    let commandsWithOptions = [];
    attrs.commands.forEach((commandId) => {
      if (typeof commandId !== "string") {
        commandId = commandId[0];
      }
      if (this.commandOptions && this.commandOptions[commandId]) {
        let options = this.commandOptions[commandId];
        let optionsWithValues = {};
        for (let optionId in options) {
          if (!options.hasOwnProperty(optionId)) {
            continue;
          }
          let option = options[optionId];
          optionsWithValues[optionId] = option.value;
        }
        commandsWithOptions.push([commandId, optionsWithValues]);
      } else {
        commandsWithOptions.push(commandId);
      }
    });
    attrs.commands = commandsWithOptions;
  }

  updateProperties() {
    let attrs = this.system
      ? this.getProperties(SYSTEM_ATTRIBUTES)
      : this.getProperties(CREATE_ATTRIBUTES);
    attrs.id = this.id;
    this.populateCommandOptions(attrs);

    return attrs;
  }

  createProperties() {
    let attrs = this.getProperties(CREATE_ATTRIBUTES);
    this.populateCommandOptions(attrs);
    return attrs;
  }

  workingCopy() {
    let attrs = this.getProperties(CREATE_ATTRIBUTES);
    this.populateCommandOptions(attrs);
    return AiPersona.create(attrs);
  }
}
