const BaseWidget = require('tkwidgets/BaseWidget.js');
const chalk = require('chalk');
const termutils = require('tkwidgets/framework/termutils.js');
const stripAnsi = require('strip-ansi');
const { handleAutocompletion } = require('../autocompletion.js');

export default class StatusBarWidget extends BaseWidget {
	public constructor() {
		super();

		this.promptState_ = null;
		this.inputEventEmitter_ = null;
		this.history_ = [];
		this.items_ = [];
	}

	public get name() {
		return 'statusBar';
	}

	public get canHaveFocus() {
		return false;
	}

	public setItemAt(index: number, text: string) {
		this.items_[index] = stripAnsi(text).trim();
		this.invalidate();
	}

	// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
	public async prompt(initialText = '', promptString: any = null, options: any = null) {
		if (this.promptState_) throw new Error('Another prompt already active');
		if (promptString === null) promptString = ':';
		if (options === null) options = {};

		this.root.globalDisableKeyboard(this);

		this.promptState_ = {
			promise: null,
			initialText: (initialText),
			promptString: stripAnsi(promptString),
		};

		if ('cursorPosition' in options) this.promptState_.cursorPosition = options.cursorPosition;
		if ('secure' in options) this.promptState_.secure = options.secure;

		this.promptState_.promise = new Promise((resolve, reject) => {
			this.promptState_.resolve = resolve;
			this.promptState_.reject = reject;
		});

		this.invalidate();

		return this.promptState_.promise;
	}

	public get promptActive() {
		return !!this.promptState_;
	}

	public get history() {
		return this.history_;
	}

	public resetCursor() {
		if (!this.promptActive) return;
		if (!this.inputEventEmitter_) return;

		this.inputEventEmitter_.redraw();
		this.inputEventEmitter_.rebase(this.absoluteInnerX + termutils.textLength(this.promptState_.promptString), this.absoluteInnerY);
		this.term.moveTo(this.absoluteInnerX + termutils.textLength(this.promptState_.promptString) + this.inputEventEmitter_.getInput().length, this.absoluteInnerY);
	}

	public render() {
		super.render();

		const doSaveCursor = !this.promptActive;

		if (doSaveCursor) this.term.saveCursor();

		this.innerClear();

		// Note:
		// On Ubuntu, bgBlueBright looks too bright which makes the white text illegible
		// On Windows, bgBlueBright is fine and looks dark enough (Windows is probably in the wrong though)
		// For now, just don't use any colour at all.

		// const textStyle = this.promptActive ? (s) => s : chalk.bgBlueBright.white;
		// const textStyle = (s) => s;
		// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
		const textStyle = this.promptActive ? (s: any) => s : chalk.gray;

		this.term.drawHLine(this.absoluteInnerX, this.absoluteInnerY, this.innerWidth, textStyle(' '));

		this.term.moveTo(this.absoluteInnerX, this.absoluteInnerY);

		if (this.promptActive) {
			this.term.write(textStyle(this.promptState_.promptString));

			if (this.inputEventEmitter_) {
				// inputField is already waiting for input so in that case just make
				// sure that the cursor is at the right position and exit.
				this.resetCursor();
				return;
			}

			this.term.showCursor(true);

			const isSecurePrompt = !!this.promptState_.secure;

			// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
			const options: any = {
				cancelable: true,
				history: this.history,
				default: this.promptState_.initialText,
				autoComplete: handleAutocompletion,
				autoCompleteHint: true,
				autoCompleteMenu: true,
			};

			if ('cursorPosition' in this.promptState_) options.cursorPosition = this.promptState_.cursorPosition;
			if (isSecurePrompt) options.echoChar = true;

			// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
			this.inputEventEmitter_ = this.term.inputField(options, (error: any, input: any) => {
				let resolveResult = null;
				const resolveFn = this.promptState_.resolve;

				if (error) {
					this.logger().error('StatusBar: inputField error:', error);
				} else {
					if (input === undefined) {
						// User cancel
					} else {
						resolveResult = input ? input.trim() : input;
						// Add the command to history but only if it's longer than one character.
						// Below that it's usually an answer like "y"/"n", etc.
						const isConfigPassword = input.indexOf('config ') >= 0 && input.indexOf('password') >= 0;
						if (!isSecurePrompt && input && input.length > 1 && !isConfigPassword) this.history_.push(input);
					}
				}

				// If the inputField spans several lines invalidate the root so that
				// the interface is relayouted.
				if (termutils.textLength(this.promptState_.promptString) + termutils.textLength(input) >= this.innerWidth - 5) {
					this.root.invalidate();
				}

				this.inputEventEmitter_ = null;
				this.term.showCursor(false);
				this.promptState_ = null;
				this.root.globalEnableKeyboard(this);
				this.invalidate();

				// Only callback once everything has been cleaned up and reset
				resolveFn(resolveResult);
			});
		} else {
			for (let i = 0; i < this.items_.length; i++) {
				const s = this.items_[i].substr(0, this.innerWidth - 1);
				this.term.write(textStyle(s));
			}
		}

		if (doSaveCursor) this.term.restoreCursor();
	}
}
