import type { VNode } from 'vue';
import type { Currency } from '../../common/enums/currency';
import type { FormItemWrapperArgs, MarginType } from '../form/form-item-wrapper';
import type { NumberRange, ValueScaling } from './plugins/currency-editor/api';
import { Component, Prop, toNative } from 'vue-facing-decorator';
import PowerduckState from '../../app/powerduck-state';
import TsxComponent from '../../app/vuetsx';
import FormItemWrapper from '../form/form-item-wrapper';
import { CurrencyDisplay } from './plugins/currency-editor/api';
import { CurrencyEditor } from './plugins/currency-editor/currency-editor';

interface CurrencyInputArgs extends FormItemWrapperArgs {
	value: number;
	maxValue?: number;
	minValue?: number;
	placeholder?: string;
	disabled?: boolean;
	readOnly?: boolean;
	changed: (newValue: number) => void;
	updateMode?: 'input' | 'change';
	nameAttr?: string;
	keyUp?: (e: KeyboardEvent) => void;
	keyDown?: (e: KeyboardEvent) => void;
	enterPressed?: (e: KeyboardEvent) => void;
	currency: Currency;
	currencyDisplay?: CurrencyDisplay;
	valueScale?: ValueScaling;
	precision?: number | NumberRange;
	grouping?: boolean;
	autoDecimalDigits?: boolean;
	localized?: boolean;
	hideCurrencySymbolOnFocus?: boolean;
	hideGroupingSeparatorOnFocus?: boolean;
	hideNegligibleDecimalDigitsOnFocus?: boolean;
}

@Component
class CurrencyInputComponent extends TsxComponent<CurrencyInputArgs> implements CurrencyInputArgs {
	@Prop() label!: string | VNode;
	@Prop() value!: number;
	@Prop() placeholder!: string;
	@Prop() cssClass!: string;
	@Prop() mandatory!: boolean;
	@Prop() disabled!: boolean;
	@Prop() readOnly?: boolean;
	@Prop() maxValue!: number;
	@Prop() minValue!: number;
	@Prop() hint: string;
	@Prop() maxWidth?: number;
	@Prop() nameAttr?: string;
	@Prop() marginType?: MarginType;
	@Prop() currency: Currency;
	@Prop() currencyDisplay?: CurrencyDisplay;
	@Prop() valueScale?: ValueScaling;
	@Prop() precision?: number | NumberRange;
	@Prop() grouping?: boolean;
	@Prop() accountingSign?: boolean;
	@Prop() autoDecimalDigits?: boolean;
	@Prop() localized?: boolean;
	@Prop() showClearValueButton!: boolean;
	@Prop() hideCurrencySymbolOnFocus?: boolean;
	@Prop() hideGroupingSeparatorOnFocus?: boolean;
	@Prop() hideNegligibleDecimalDigitsOnFocus?: boolean;
	@Prop() keyDown: (e: KeyboardEvent) => void;
	@Prop() keyUp: (e: KeyboardEvent) => void;
	@Prop() enterPressed: (e: KeyboardEvent) => void;
	@Prop() changed: (newValue: number) => void;
	@Prop() updateMode?: 'input' | 'change';

	mounted() {
		// eslint-disable-next-line no-new
		new CurrencyEditor({
			el: this.getInputElement(),
			options: {
				currency: this.currency,
				currencyDisplay: this.currencyDisplay ?? CurrencyDisplay.symbol,
				hideCurrencySymbolOnFocus: this.hideCurrencySymbolOnFocus ?? false,
				hideGroupingSeparatorOnFocus: this.hideGroupingSeparatorOnFocus ?? false,
				hideNegligibleDecimalDigitsOnFocus: this.hideNegligibleDecimalDigitsOnFocus ?? true,
				precision: this.precision ?? 0,
				valueRange: {
					min: this.minValue,
					max: this.maxValue,
				},
				accountingSign: this.accountingSign ?? false,
				autoDecimalDigits: this.autoDecimalDigits ?? false,
				useGrouping: this.grouping ?? true,
				valueScaling: this.valueScale,
			},
			onInput: (e) => {
				if (this.updateMode == 'input') {
					this.raiseChangeEvent(e);
				}
			},
			onChange: (e) => {
				this.raiseChangeEvent(e);
			},
		});

		if (this.keyDown != null || this.enterPressed != null) {
			this.$el.querySelector('input').addEventListener('keydown', (e) => {
				this.keyDownHandler(e);
			});
		}

		if (this.keyUp != null) {
			this.$el.querySelector('input').addEventListener('keyup', (e) => {
				this.keyUpHandler(e);
			});
		}
	}

	getInputElement() {
		return this.$el.querySelector('input');
	}

	raiseChangeEvent(e) {
		this.populateValidationDeclaration();

		if (this.changed != null) {
			let newValue = e.number;
			newValue = parseFloat(newValue) || 0;

			if (this.minValue != null && newValue < this.minValue) {
				newValue = this.minValue;
			}

			if (this.maxValue != null && newValue > this.maxValue) {
				newValue = this.maxValue;
			}

			this.changed(newValue);
		}
	}

	keyDownHandler(e: KeyboardEvent) {
		if (this.keyDown != null) {
			this.keyDown(e);
		}

		if (this.enterPressed != null && (e.keyCode === 13 || e.which === 13)) {
			this.raiseChangeEvent(e);
			this.enterPressed(e);
			e.preventDefault();
			e.stopPropagation();
			e.stopImmediatePropagation();
		}
	}

	keyUpHandler(e: KeyboardEvent) {
		if (this.keyUp != null) {
			this.keyUp(e);
		}

		if (this.enterPressed != null && (e.keyCode == 13 || e.which == 13)) {
			this.raiseChangeEvent(e);
			this.enterPressed(e);
			e.preventDefault();
			e.stopPropagation();
			e.stopImmediatePropagation();
		}
	}

	render(h) {
		return (
			<FormItemWrapper label={this.label} cssClass={this.cssClass} mandatory={this.mandatory} marginType={this.marginType} hint={this.hint} maxWidth={this.maxWidth} showClearValueButton={this.showClearValueButton}>
				<input
					type="text"
					disabled={this.disabled != true ? null : 'disabled'}
					readonly={this.readOnly != true ? null : 'readonly'}
					name={this.nameAttr}
					class={PowerduckState.getFormControlCssClass()}
					placeholder={this.placeholder}
				/>
			</FormItemWrapper>
		);
	}
}

const CurrencyInput = toNative(CurrencyInputComponent);
export default CurrencyInput;
