import { getRequestHeaders, substituteParams } from '../../../../script.js';
import { executeSlashCommands, executeSlashCommandsOnChatInput, executeSlashCommandsWithOptions } from '../../../slash-commands.js';
import { SlashCommandScope } from '../../../slash-commands/SlashCommandScope.js';
import { debounceAsync, warn } from '../index.js';
import { QuickReply } from './QuickReply.js';

export class QuickReplySet {
    /**@type {QuickReplySet[]}*/ static list = [];


    static from(props) {
        props.qrList = []; //props.qrList?.map(it=>QuickReply.from(it));
        const instance = Object.assign(new this(), props);
        // instance.init();
        return instance;
    }

    /**
     * @param {String} name - name of the QuickReplySet
     */
    static get(name) {
        return this.list.find(it=>it.name == name);
    }




    /**@type {String}*/ name;
    /**@type {Boolean}*/ disableSend = false;
    /**@type {Boolean}*/ placeBeforeInput = false;
    /**@type {Boolean}*/ injectInput = false;
    /**@type {QuickReply[]}*/ qrList = [];

    /**@type {Number}*/ idIndex = 0;

    /**@type {Boolean}*/ isDeleted = false;

    /**@type {Function}*/ save;

    /**@type {HTMLElement}*/ dom;
    /**@type {HTMLElement}*/ settingsDom;




    constructor() {
        this.save = debounceAsync(()=>this.performSave(), 200);
    }

    init() {
        this.qrList.forEach(qr=>this.hookQuickReply(qr));
    }




    unrender() {
        this.dom?.remove();
        this.dom = null;
    }
    render() {
        this.unrender();
        if (!this.dom) {
            const root = document.createElement('div'); {
                this.dom = root;
                root.classList.add('qr--buttons');
                this.qrList.filter(qr=>!qr.isHidden).forEach(qr=>{
                    root.append(qr.render());
                });
            }
        }
        return this.dom;
    }
    rerender() {
        if (!this.dom) return;
        this.dom.innerHTML = '';
        this.qrList.filter(qr=>!qr.isHidden).forEach(qr=>{
            this.dom.append(qr.render());
        });
    }




    renderSettings() {
        if (!this.settingsDom) {
            this.settingsDom = document.createElement('div'); {
                this.settingsDom.classList.add('qr--set-qrListContents');
                this.qrList.forEach((qr,idx)=>{
                    this.renderSettingsItem(qr, idx);
                });
            }
        }
        return this.settingsDom;
    }
    renderSettingsItem(qr, idx) {
        this.settingsDom.append(qr.renderSettings(idx));
    }




    /**
     *
     * @param {QuickReply} qr The QR to execute.
     * @param {object} options
     * @param {string} [options.message] (null) altered message to be used
     * @param {boolean} [options.isAutoExecute] (false) whether the execution is triggered by auto execute
     * @param {boolean} [options.isEditor] (false) whether the execution is triggered by the QR editor
     * @param {boolean} [options.isRun] (false) whether the execution is triggered by /run or /: (window.executeQuickReplyByName)
     * @param {SlashCommandScope} [options.scope] (null) scope to be used when running the command
     * @returns
     */
    async executeWithOptions(qr, options = {}) {
        options = Object.assign({
            message:null,
            isAutoExecute:false,
            isEditor:false,
            isRun:false,
            scope:null,
        }, options);
        /**@type {HTMLTextAreaElement}*/
        const ta = document.querySelector('#send_textarea');
        const finalMessage = options.message ?? qr.message;
        let input = ta.value;
        if (!options.isAutoExecute && !options.isEditor && !options.isRun && this.injectInput && input.length > 0) {
            if (this.placeBeforeInput) {
                input = `${finalMessage} ${input}`;
            } else {
                input = `${input} ${finalMessage}`;
            }
        } else {
            input = `${finalMessage} `;
        }

        if (input[0] == '/' && !this.disableSend) {
            let result;
            if (options.isAutoExecute || options.isRun) {
                result = await executeSlashCommandsWithOptions(input, {
                    handleParserErrors: true,
                    scope: options.scope,
                });
            } else if (options.isEditor) {
                result = await executeSlashCommandsWithOptions(input, {
                    handleParserErrors: false,
                    scope: options.scope,
                    abortController: qr.abortController,
                    onProgress: (done, total) => qr.updateEditorProgress(done, total),
                });
            } else {
                result = await executeSlashCommandsOnChatInput(input, {
                    scope: options.scope,
                });
            }
            return typeof result === 'object' ? result?.pipe : '';
        }

        ta.value = substituteParams(input);
        ta.focus();

        if (!this.disableSend) {
            // @ts-ignore
            document.querySelector('#send_but').click();
        }
    }
    /**
     * @param {QuickReply} qr
     * @param {String} [message] - optional altered message to be used
     * @param {SlashCommandScope} [scope] - optional scope to be used when running the command
     */
    async execute(qr, message = null, isAutoExecute = false, scope = null) {
        return this.executeWithOptions(qr, {
            message,
            isAutoExecute,
            scope,
        });
    }




    addQuickReply() {
        const id = Math.max(this.idIndex, this.qrList.reduce((max,qr)=>Math.max(max,qr.id),0)) + 1;
        this.idIndex = id + 1;
        const qr = QuickReply.from({ id });
        this.qrList.push(qr);
        this.hookQuickReply(qr);
        if (this.settingsDom) {
            this.renderSettingsItem(qr, this.qrList.length - 1);
        }
        if (this.dom) {
            this.dom.append(qr.render());
        }
        this.save();
        return qr;
    }

    hookQuickReply(qr) {
        qr.onExecute = (_, options)=>this.executeWithOptions(qr, options);
        qr.onDelete = ()=>this.removeQuickReply(qr);
        qr.onUpdate = ()=>this.save();
    }

    removeQuickReply(qr) {
        this.qrList.splice(this.qrList.indexOf(qr), 1);
        this.save();
    }


    toJSON() {
        return {
            version: 2,
            name: this.name,
            disableSend: this.disableSend,
            placeBeforeInput: this.placeBeforeInput,
            injectInput: this.injectInput,
            qrList: this.qrList,
            idIndex: this.idIndex,
        };
    }


    async performSave() {
        const response = await fetch('/api/quick-replies/save', {
            method: 'POST',
            headers: getRequestHeaders(),
            body: JSON.stringify(this),
        });

        if (response.ok) {
            this.rerender();
        } else {
            warn(`Failed to save Quick Reply Set: ${this.name}`);
        }
    }

    async delete() {
        const response = await fetch('/api/quick-replies/delete', {
            method: 'POST',
            headers: getRequestHeaders(),
            body: JSON.stringify(this),
        });

        if (response.ok) {
            this.unrender();
            const idx = QuickReplySet.list.indexOf(this);
            QuickReplySet.list.splice(idx, 1);
            this.isDeleted = true;
        } else {
            warn(`Failed to delete Quick Reply Set: ${this.name}`);
        }
    }
}
