// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
import * as readline from 'node:readline';
import * as process from 'node:process';
import { AnsiEscape, Colorize } from '@rushstack/terminal';
import { KeyboardLoop } from './KeyboardLoop';
class YesNoKeyboardLoop extends KeyboardLoop {
    constructor(options) {
        super();
        this.result = undefined;
        this.options = options;
    }
    onStart() {
        this.stderr.write(Colorize.green('==>') + ' ');
        this.stderr.write(Colorize.bold(this.options.message));
        let optionSuffix = '';
        switch (this.options.defaultValue) {
            case true:
                optionSuffix = '(Y/n)';
                break;
            case false:
                optionSuffix = '(y/N)';
                break;
            default:
                optionSuffix = '(y/n)';
                break;
        }
        this.stderr.write(' ' + Colorize.bold(optionSuffix) + ' ');
    }
    onKeypress(character, key) {
        if (this.result !== undefined) {
            return;
        }
        switch (key.name) {
            case 'y':
                this.result = true;
                break;
            case 'n':
                this.result = false;
                break;
            case 'enter':
            case 'return':
                if (this.options.defaultValue !== undefined) {
                    this.result = this.options.defaultValue;
                }
                break;
        }
        if (this.result !== undefined) {
            this.stderr.write(this.result ? 'Yes\n' : 'No\n');
            this.resolveAsync();
            return;
        }
    }
}
class PasswordKeyboardLoop extends KeyboardLoop {
    constructor(options) {
        super();
        this._startX = 0;
        this._printedY = 0;
        this._lastPrintedLength = 0;
        this.result = '';
        this._options = options;
        this._passwordCharacter =
            this._options.passwordCharacter === undefined ? '*' : this._options.passwordCharacter.substr(0, 1);
    }
    _getLineWrapWidth() {
        return this.stderr.columns ? this.stderr.columns : 80;
    }
    onStart() {
        this.result = '';
        readline.cursorTo(this.stderr, 0);
        readline.clearLine(this.stderr, 1);
        const prefix = Colorize.green('==>') + ' ' + Colorize.bold(this._options.message) + ' ';
        this.stderr.write(prefix);
        let lineStartIndex = prefix.lastIndexOf('\n');
        if (lineStartIndex < 0) {
            lineStartIndex = 0;
        }
        const line = prefix.substring(lineStartIndex);
        this._startX = AnsiEscape.removeCodes(line).length % this._getLineWrapWidth();
    }
    onKeypress(character, key) {
        switch (key.name) {
            case 'enter':
            case 'return':
                if (this._passwordCharacter !== '') {
                    // To avoid disclosing the length of the password, after the user presses ENTER,
                    // replace the "*********" sequence with exactly three stars ("***").
                    this._render(this._passwordCharacter.repeat(3));
                }
                this.stderr.write('\n');
                this.resolveAsync();
                return;
            case 'backspace':
                this.result = this.result.substring(0, this.result.length - 1);
                this._render(this.result);
                break;
            default:
                let printable = true;
                if (character === '') {
                    printable = false;
                }
                else if (key.name && key.name.length !== 1 && key.name !== 'space') {
                    printable = false;
                }
                else if (!key.name && !key.sequence) {
                    printable = false;
                }
                if (printable) {
                    this.result += character;
                    this._render(this.result);
                }
        }
    }
    _render(text) {
        // Optimize rendering when we don't need to erase anything
        const needsClear = text.length < this._lastPrintedLength;
        this._lastPrintedLength = text.length;
        this.hideCursor();
        // Restore Y
        while (this._printedY > 0) {
            readline.cursorTo(this.stderr, 0);
            if (needsClear) {
                readline.clearLine(this.stderr, 1);
            }
            readline.moveCursor(this.stderr, 0, -1);
            --this._printedY;
        }
        // Restore X
        readline.cursorTo(this.stderr, this._startX);
        let i = 0;
        let column = this._startX;
        this._printedY = 0;
        let buffer = '';
        while (i < text.length) {
            if (this._passwordCharacter === '') {
                buffer += text.substr(i, 1);
            }
            else {
                buffer += this._passwordCharacter;
            }
            ++i;
            ++column;
            // -1 to avoid weird TTY behavior in final column
            if (column >= this._getLineWrapWidth() - 1) {
                column = 0;
                ++this._printedY;
                buffer += '\n';
            }
        }
        this.stderr.write(buffer);
        if (needsClear) {
            readline.clearLine(this.stderr, 1);
        }
        this.unhideCursor();
    }
}
export class TerminalInput {
    static async _readLineAsync() {
        const readlineInterface = readline.createInterface({ input: process.stdin });
        try {
            return await new Promise((resolve, reject) => {
                readlineInterface.question('', (answer) => {
                    resolve(answer);
                });
            });
        }
        finally {
            readlineInterface.close();
        }
    }
    static async promptYesNoAsync(options) {
        const keyboardLoop = new YesNoKeyboardLoop(options);
        await keyboardLoop.startAsync();
        return keyboardLoop.result;
    }
    static async promptLineAsync(options) {
        const stderr = process.stderr;
        stderr.write(Colorize.green('==>') + ' ');
        stderr.write(Colorize.bold(options.message));
        stderr.write(' ');
        return await TerminalInput._readLineAsync();
    }
    static async promptPasswordLineAsync(options) {
        const keyboardLoop = new PasswordKeyboardLoop(options);
        await keyboardLoop.startAsync();
        return keyboardLoop.result;
    }
}
//# sourceMappingURL=TerminalInput.js.map