<commit_before>import { WebClient } from "@slack/web-api";
import { DynamicLoader } from "bcdice";
import { GameSystemInfo } from "bcdice/lib/bcdice/game_system_list.json";
import GameSystemClass from "bcdice/lib/game_system";
import type { SlackInterface } from "../lib/slack";

interface Message {
  type: string;
  subtype: string;
  text: string;
  ts: string;
  username: string;
  icons: { emoji: ":game_die:" };
  bot_id: string;
  app_id: string;
  channel: string;
  event_ts: string;
  channel_type: string;
}

function unescapeHtml(str: string) {
  return str.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
}

class DiceBot {
  slack: WebClient;
  loader: DynamicLoader;
  gameSystem: GameSystemClass;

  constructor({ webClient: slack, eventClient }: SlackInterface) {
    this.slack = slack;
    this.loader = new DynamicLoader();

    eventClient.on("message", async (message: Message) => {
      if (!DiceBot.validateMessage(message)) return;

      const text = unescapeHtml(message.text);

      if (text.startsWith("@dicebot ")) {
        this.handleCommand(DiceBot.parseCommand(text));
      } else {
        await this.handleMessage(text);
      }
    });
  }

  async setGameSystem(systemName: string) {
    this.gameSystem = await this.loader.dynamicLoad(systemName);
  }

  async sendMessage(text: string) {
    await this.slack.chat.postMessage({
      channel: process.env.CHANNEL_SANDBOX,
      username: "dicebot",
      icon_emoji: ":game_die:",
      icon_url: "",
      text: text,
    });
  }

  async handleMessage(text: string) {
    const result = this.gameSystem.eval(text);
    if (result?.text) this.sendMessage(result.text);
  }

  async handleCommand(args: string[]) {
    const command = args[0];
    switch (command) {
      case "system":
        if (args.length >= 2) {
          try {
            await this.setGameSystem(args[1]);
            this.sendMessage(
              `ゲームシステムを ${this.gameSystem.NAME} にセットしたよ`
            );
          } catch (e) {
            this.sendMessage(
              `${args[1]} は知らないゲームシステムだよ\nIDで指定してね\nシステムの一覧は @dicebot list で確認できるよ`
            );
          }
        } else {
          this.sendMessage(`今のゲームシステムは ${this.gameSystem.NAME} だよ`);
        }
        break;
      case "systemhelp":
        this.sendMessage(this.gameSystem.HELP_MESSAGE);
        break;
      case "list":
        this.sendMessage(`以下のシステムが指定できるよ\nNAME: ID`);
        this.sendMessage(DiceBot.getLoadedSystemsName(this.loader));
        break;
      case "help":
        this.sendMessage(DiceBot.helpMessage);
        break;
      default:
        this.sendMessage(`知らないコマンドだよ`);
        this.sendMessage(DiceBot.helpMessage);
        break;
    }
  }

  static helpMessage: string = `\
@dicebot help: このヘルプを表示
@dicebot system: 現在のゲームシステムを確認<commit_msg>Add await before sendMessage<commit_after>import { WebClient } from "@slack/web-api";
import { DynamicLoader } from "bcdice";
import { GameSystemInfo } from "bcdice/lib/bcdice/game_system_list.json";
import GameSystemClass from "bcdice/lib/game_system";
import type { SlackInterface } from "../lib/slack";

interface Message {
  type: string;
  subtype: string;
  text: string;
  ts: string;
  username: string;
  icons: { emoji: ":game_die:" };
  bot_id: string;
  app_id: string;
  channel: string;
  event_ts: string;
  channel_type: string;
}

function unescapeHtml(str: string) {
  return str.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
}

class DiceBot {
  slack: WebClient;
  loader: DynamicLoader;
  gameSystem: GameSystemClass;

  constructor({ webClient: slack, eventClient }: SlackInterface) {
    this.slack = slack;
    this.loader = new DynamicLoader();

    eventClient.on("message", async (message: Message) => {
      if (!DiceBot.validateMessage(message)) return;

      const text = unescapeHtml(message.text);

      if (text.startsWith("@dicebot ")) {
        this.handleCommand(DiceBot.parseCommand(text));
      } else {
        await this.handleMessage(text);
      }
    });
  }

  async setGameSystem(systemName: string) {
    this.gameSystem = await this.loader.dynamicLoad(systemName);
  }

  async sendMessage(text: string) {
    await this.slack.chat.postMessage({
      channel: process.env.CHANNEL_SANDBOX,
      username: "dicebot",
      icon_emoji: ":game_die:",
      icon_url: "",
      text: text,
    });
  }

  async handleMessage(text: string) {
    const result = this.gameSystem.eval(text);
    if (result?.text) await this.sendMessage(result.text);
  }

  async handleCommand(args: string[]) {
    const command = args[0];
    switch (command) {
      case "system":
        if (args.length >= 2) {
          try {
            await this.setGameSystem(args[1]);
            await this.sendMessage(
              `ゲームシステムを ${this.gameSystem.NAME} にセットしたよ`
            );
          } catch (e) {
            await this.sendMessage(
              `${args[1]} は知らないゲームシステムだよ\nIDで指定してね\nシステムの一覧は @dicebot list で確認できるよ`
            );
          }
        } else {
          await this.sendMessage(`今のゲームシステムは ${this.gameSystem.NAME} だよ`);
        }
        break;
      case "systemhelp":
        await this.sendMessage(this.gameSystem.HELP_MESSAGE);
        break;
      case "list":
        await this.sendMessage(`以下のシステムが指定できるよ\nNAME: ID`);
        await this.sendMessage(DiceBot.getLoadedSystemsName(this.loader));
        break;
      case "help":
        await this.sendMessage(DiceBot.helpMessage);
        break;
      default:
        await this.sendMessage(`知らないコマンドだよ`);
        await this.sendMessage(DiceBot.helpMessage);
        break;
    }
  }


  static helpMessage: string = `\
@dicebot help: このヘルプを表示
@dicebot system: 現在のゲームシステムを確認
{'fraction_non_alphanumeric': 0.13321739130434782, 'fraction_numerical': 0.001391304347826087, 'mean_word_length': 2.75146771037182, 'pattern_counts': {'":': 12, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3692684', 'n_tokens_mistral': 2002, 'n_tokens_neox': 1995, 'n_words': 364}