import { Plugin, Event, BotEventData, Command, ICommandData } from "src/model/plugin";
import { readdirSync, statSync } from "fs";
import { join, basename, extname } from "path";
import { Message } from "discord.js";
import { tryDo } from "src/util";
import { logger } from "src/logging";

const STICKERS_PATH = "./stickers";
const STICKERS_PREFIX = "!";
const STICKERS_PER_ROW = 5;
const ROWS_PER_MESSAGE = 30;

@Plugin
export class Stickers {
    stickers: Record<string, string> = {};

    @Event("message")
    async onMessage(data: BotEventData, msg: Message): Promise<void> {
        if (data.actionsDone)
            return;

        const lowerContent = msg.cleanContent.trim().toLowerCase();
        if (!lowerContent.startsWith(STICKERS_PREFIX))
            return;

        const stickerName = lowerContent.substr(1);
        if (!(stickerName in this.stickers))
            return;

        const deleteResult = await tryDo(msg.delete());
        if (!deleteResult.ok) {
            logger.error("Stickers: failed to delete message %s from user %s. Reason: %s", msg.id, msg.author.id, deleteResult.error);
        }
        const sendResult = await tryDo(msg.channel.send(`${msg.author.toString()} *sent a sticker:*`, {
            files: [this.stickers[stickerName]]
        }));

        if (!sendResult.ok) {
            logger.error("Stickers: failed to send sticker to channel %s. Reason: %s", msg.channel.id, sendResult.error);
        }
        data.actionsDone = true;
    }

    @Command({
        type: "mention",
        pattern: "stickers",
        auth: false,
        documentation: { description: "Lists all available stickers", example: "stickers" }
    })
    async listStickers({ message }: ICommandData): Promise<void> {
        const stickerNames = Object.keys(this.stickers)
            .filter(s => Object.prototype.hasOwnProperty.call(this.stickers, s));
        const maxLength = stickerNames.map(s => s.length).reduce((prev, cur) => Math.max(prev, cur), 0);
        const m = stickerNames.reduce((prev, cur, i) => `${prev}!${cur}${" ".repeat(maxLength - cur.length + 2)}${(i + 1) % STICKERS_PER_ROW == 0 ? "\n" : ""}`, "");
        
        let toSend = `${message.author.toString()}, I have the following stickers:\n\`\`\``;
        const rows = m.split("\n");
        for (let i = 0; i < rows.length; i++) {
            toSend += `${rows[i]}\n`;
            if (i != 0 && i % ROWS_PER_MESSAGE == 0) {
                toSend += "```";
                await message.channel.send(toSend);
                toSend = "```\n";
            }
        }
        toSend += "```\n";
        toSend += "To use stickers, simply use their name. Example: !hackermaid";
        await message.channel.send(toSend);
    }

    async start(): Promise<void> {
        const files = readdirSync(STICKERS_PATH).filter(f => !statSync(join(STICKERS_PATH, f)).isDirectory());
        for (const file of files)
            this.stickers[basename(file, extname(file)).toLowerCase()] = join(STICKERS_PATH, file);
        logger.info("Found %s stickers", Object.keys(this.stickers).length);
    }
}