import { css, customElement, html, ifDefined, property, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbNumberRangeValueType } from '@umbraco-cms/backoffice/models';
import type { UUIInputElement } from '@umbraco-cms/backoffice/external/uui';

/**
 *
 * @param value
 */
function getNumberOrUndefined(value: string) {
	const num = parseInt(value, 10);
	return isNaN(num) ? undefined : num;
}

@customElement('umb-input-number-range')
export class UmbInputNumberRangeElement extends UmbFormControlMixin(UmbLitElement) {
	@property({ type: String, attribute: 'min-label' })
	minLabel = 'Low value';

	@property({ type: String, attribute: 'max-label' })
	maxLabel = 'High value';

	@state()
	private _minValue?: number;

	@property({ type: Number })
	public set minValue(value: number | undefined) {
		this._minValue = value;
		this.#updateValue();
	}
	public get minValue() {
		return this._minValue;
	}

	@property({ type: Boolean })
	required = false;
	@property({ type: String })
	requiredMessage = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY;

	@state()
	private _maxValue?: number;

	@property({ type: Number })
	public set maxValue(value: number | undefined) {
		this._maxValue = value;
		this.#updateValue();
	}
	public get maxValue() {
		return this._maxValue;
	}

	@property({ type: Object })
	public set validationRange(value: UmbNumberRangeValueType | undefined) {
		this.#validationRange = value;
		this._minPlaceholder = value?.min !== undefined ? String(value?.min) : '';
		this._maxPlaceholder = value?.max !== undefined && value.max !== Infinity ? String(value.max) : '∞';
	}
	public get validationRange(): UmbNumberRangeValueType | undefined {
		return this.#validationRange;
	}
	#validationRange?: UmbNumberRangeValueType | undefined;

	@state()
	private _minPlaceholder: string = '';

	@state()
	private _maxPlaceholder: string = '';

	#updateValue() {
		const newValue =
			this._minValue || this._maxValue ? (this._minValue ?? '') + ',' + (this._maxValue ?? '') : undefined;
		if (super.value !== newValue) {
			super.value = newValue;
		}
	}

	@property()
	public override set value(valueString: string | undefined) {
		if (valueString !== this.value) {
			if (valueString === undefined) {
				this.minValue = this.maxValue = undefined;
				return;
			}
			const splittedValue = valueString.split(/[ ,]+/);
			this.minValue = getNumberOrUndefined(splittedValue[0]);
			this.maxValue = getNumberOrUndefined(splittedValue[1]);
		}
	}
	public override get value(): string | undefined {
		return this.minValue || this.maxValue ? (this.minValue || '') + ',' + (this.maxValue || '') : undefined;
	}

	constructor() {
		super();

		this.addValidator(
			'valueMissing',
			() => this.requiredMessage,
			() => this.required && (this._minValue == null || this._maxValue == null),
		);

		this.addValidator(
			'patternMismatch',
			() => {
				return '#validation_rangeExceeds';
			},
			() => {
				return this._minValue !== undefined && this._maxValue !== undefined ? this._minValue > this._maxValue : false;
			},
		);
	}

	override firstUpdated() {
		this.shadowRoot?.querySelectorAll<UUIInputElement>('uui-input').forEach((x) => this.addFormControlElement(x));
	}

	override focus() {
		return this.shadowRoot?.querySelector<UUIInputElement>('uui-input')?.focus();
	}

	#onMinInput(e: InputEvent & { target: HTMLInputElement }) {
		const value = e.target.value;
		this.minValue = value ? Number(value) : undefined;
		this.dispatchEvent(new UmbChangeEvent());
	}

	#onMaxInput(e: InputEvent & { target: HTMLInputElement }) {
		const value = e.target.value;
		this.maxValue = value ? Number(value) : undefined;
		this.dispatchEvent(new UmbChangeEvent());
	}

	override render() {
		return html`
			<uui-input
				type="number"
				label=${this.minLabel}
				min=${ifDefined(this.validationRange?.min)}
				max=${ifDefined(this.validationRange?.max)}
				placeholder=${this._minPlaceholder}
				?required=${this.required}
				.value=${this._minValue?.toString() ?? ''}
				@input=${this.#onMinInput}></uui-input>
			<b>–</b>
			<uui-input
				type="number"
				label=${this.maxLabel}
				min=${ifDefined(this.validationRange?.min)}
				max=${ifDefined(this.validationRange?.max)}
				placeholder=${this._maxPlaceholder}
				?required=${this.required}
				.value=${this._maxValue?.toString() ?? ''}
				@input=${this.#onMaxInput}></uui-input>
		`;
	}

	static override styles = css`
		:host {
			display: flex;
			align-items: center;
		}
		b {
			margin: 0 var(--uui-size-space-1);
		}
		:host(:invalid:not([pristine])) {
			color: var(--uui-color-invalid);
		}
		:host(:invalid:not([pristine])) uui-input {
			border-color: var(--uui-color-invalid);
		}
	`;
}

export default UmbInputNumberRangeElement;

declare global {
	interface HTMLElementTagNameMap {
		'umb-input-number-range': UmbInputNumberRangeElement;
	}
}
