import {
    ProcessText,
    LoadCurrentBuffer,
    SaveCurrentBuffer,
} from "../wailsjs/go/main/App";

class TextProcessor {
    constructor() {
        this._lastAutoSave = undefined;
    }

    setCodeMirrorEditor(editor) {
        this._editor = editor;
        window.runtime.EventsOn("process-text-response", (data) => {
            const cursorPos = this._editor.state.selection.main.head;
            const appendInsertPos = this._appendInsertPos;
            this._appendInsertPos = undefined;
            let newSelection;
            const changes = data.output.map(span => {
                if (span.append) {
                    const insertAt = appendInsertPos !== undefined ? appendInsertPos : span.pos + span.len;
                    if (cursorPos === insertAt) {
                        newSelection = { anchor: insertAt + span.text.length };
                    }
                    return {
                        from: insertAt,
                        to: insertAt,
                        insert: span.text,
                    };
                } else {
                    return {
                        from: span.pos,
                        to: span.pos + span.len,
                        insert: span.text,
                    };
                }
            });
            const transaction = { changes: changes };
            if (newSelection) {
                transaction.selection = newSelection;
            }
            this._editor.dispatch(transaction);
        });
        window.runtime.EventsOn("request-text-process", (data) => {
            this.runTextCommand(data.action);
        });
    }

    async runTextCommand(command) {
        if (this._editor === undefined) {
            return;
        }

        let ranges = this._editor.state.selection.ranges;
        let shouldBeAll = ranges.reduce((a, r) => a && r.from === r.to, true);

        let inputs = [];
        if (shouldBeAll) {
            this._appendInsertPos = this._editor.state.selection.main.head;
            inputs.push({
                text: this._editor.state.doc.toString(),
                pos: 0,
                len: this._editor.state.doc.length,
            });
        } else {
            this._appendInsertPos = undefined;
            inputs = ranges.map(r => ({
                text: this._editor.state.doc.slice(r.from, r.to).toString(),
                pos: r.from,
                len: r.to - r.from,
            }))
        }

        await ProcessText({
            action: command,
            input: inputs,
        });
        await this.saveBuffer();
    }

    async loadCurrentBuffer() {
        let buffer = await LoadCurrentBuffer();
        this._editor.dispatch({ changes: { from: 0, to: this._editor.state.doc.length, insert: buffer } });
        this._lastAutoSave = buffer;
    }

    startAutoSaver() {
        setInterval(() => {
            this.saveBuffer();
        }, 1000);
    }

    async saveBuffer(force) {
        let buffer = this._editor.state.doc.toString();
        if (force || (buffer !== this._lastAutoSave)) {
            this._lastAutoSave = buffer;
            await SaveCurrentBuffer(buffer);
        }
    }
}

export const textProcessor = new TextProcessor();