import * as utils from "../../utils/index";
import { ComponentNPC } from "./base";
import { Companion } from "../companion";
export class DialogueComponentMessage {
    constructor(data) {
        var _a;
        this.messageList = data.messageList;
        this.key = data.key;
        this.priority = (_a = data.priority) !== null && _a !== void 0 ? _a : 0;
    }
    async displayMessage(player) {
        var _a;
        const message = utils.getRandomArrayEntry(this.messageList);
        const volume = (_a = utils.readDynamicProperty(player, 'volume')) !== null && _a !== void 0 ? _a : 1;
        player.playSound(message.sound, { volume });
        player.sendMessage(message.message);
        await utils.waitForTicks(message.duration * 20, player.id + "_sound");
    }
    abort(player) {
        this.messageList.forEach(message => { player.runCommand(`stopsound @s ${message.sound}`); });
        utils.abortEvents(player.id + "_sound");
    }
}
export class DialogueComponent extends ComponentNPC {
    constructor(dialogueMessages) {
        super();
        this.callbacks = [];
        this.dialogueMessages = dialogueMessages;
    }
    async onComponentAdded(npc) {
        super.onComponentAdded(npc);
        if (npc instanceof Companion) {
            utils.mclog(`${this.id} Subscribing To Broadcast Events (${npc.ID})`);
            Object.keys(this.dialogueMessages).forEach(key => {
                const callback = () => { this.addDialogueToQueue(npc.Owner, key); };
                this.callbacks.push(callback);
                npc.subscribeToBroadcast(key, callback);
            });
            if (this.getPlayerQueue(npc.Owner).isPlaying) {
                this.playQueue(npc.Owner);
            }
        }
    }
    async onComponentRemoved(npc) {
        super.onComponentRemoved(npc);
        if (npc instanceof Companion) {
            utils.mclog(`${this.id} Unsubscribing To Broadcast Events (${npc.ID})`);
            Object.keys(this.dialogueMessages).forEach((key, index) => {
                const callback = this.callbacks[index];
                npc.unsubscribeToBroadcast(key, callback);
            });
        }
    }
    getPlayerQueue(player) {
        var _a;
        return (_a = utils.readDynamicProperty(player, "dialogueQueue")) !== null && _a !== void 0 ? _a : { messageKeys: [], isPlaying: false };
    }
    setPlayerQueue(player, queue) {
        utils.writeDynamicProperty(player, "dialogueQueue", queue);
    }
    addDialogueToQueue(player, dialogueKey) {
        if (utils.getScoreAsBool(".var", "YouTube"))
            return;
        const queue = this.getPlayerQueue(player);
        const message = this.dialogueMessages[dialogueKey];
        if (!message) {
            utils.mcerror(`No Dialogue Message With Key: ${dialogueKey}`, "npc");
            return;
        }
        queue.messageKeys.push(dialogueKey);
        if (queue.currentMessage && message.priority >= this.dialogueMessages[queue.currentMessage].priority) {
            queue.isPlaying = false;
            this.dialogueMessages[queue.currentMessage].abort(player);
            utils.mcwarn(`Aborting Dialogue ${queue.currentMessage}`);
        }
        this.setPlayerQueue(player, queue);
        if (!queue.isPlaying) {
            this.playQueue(player);
        }
    }
    async playQueue(player) {
        let queue = this.getPlayerQueue(player);
        let highestPriorityMessage = queue.messageKeys.map(key => this.dialogueMessages[key]).sort((a, b) => a.priority - b.priority)[0];
        while (highestPriorityMessage) {
            utils.removeFromArray(queue.messageKeys, highestPriorityMessage.key);
            queue.currentMessage = highestPriorityMessage.key;
            queue.isPlaying = true;
            this.setPlayerQueue(player, queue);
            await highestPriorityMessage.displayMessage(player);
            queue = this.getPlayerQueue(player);
            highestPriorityMessage = queue.messageKeys.map(key => this.dialogueMessages[key]).sort((a, b) => a.priority - b.priority)[0];
        }
        queue.isPlaying = false;
        this.setPlayerQueue(player, queue);
    }
    clearQueue(player) {
        const queue = this.getPlayerQueue(player);
        if (queue.currentMessage) {
            this.dialogueMessages[queue.currentMessage].abort(player);
        }
        this.setPlayerQueue(player, { messageKeys: [], isPlaying: false });
    }
}
