// @ts-ignore
import React from "react";
import { BlikFieldPropsInterface } from "./interfaces/BlikFieldPropsInterface";
import { BlikFieldStateInterface } from "./interfaces/BlikFieldStateInterface";
import { MessagesService } from "../MessagesService";
import { SimplyinPaymentMethod } from "../simplyinPayments";

declare global {
	interface Window {
		SimplyIn?: {
			validatePhoneNumber?: () => boolean;
		};
	}
}

interface BlikDigitState {
	value: string;
	filled: boolean;
	valid: boolean;
	error: boolean;
}

interface BlikNumberExtendedState extends BlikFieldStateInterface {
	digits: BlikDigitState[];
	focusedIndex: number;
	isComplete: boolean;
}

export class BlikField extends React.Component<
	BlikFieldPropsInterface,
	BlikNumberExtendedState
> {
	private inputRefs: React.RefObject<HTMLInputElement>[] = [];

	constructor(props: BlikFieldPropsInterface) {
		super(props);

		for (let i = 0; i < 6; i++) {
			this.inputRefs.push(React.createRef<HTMLInputElement>());
		}

		this.state = {
			blikCode: "",
			blikError: "",
			digits: Array(6)
				.fill(null)
				.map(() => ({
					value: "",
					filled: false,
					valid: false,
					error: false,
				})),
			focusedIndex: -1,
			isComplete: false,
		};
	}

	render() {
		return (
			<div className="simplyin-blik-field-container active">
				<div className="simplyin-blik-input-wrapper">
					<div className="simplyin-blik-inputs-grid">
						{this.state.digits.map((digit, index) => (
							<input
								key={index}
								ref={this.inputRefs[index]}
								type="text"
								inputMode="numeric"
								maxLength={1}
								value={digit.value}
								className={`simplyin-blik-digit-input ${
									digit.filled ? "filled" : ""
								} ${digit.valid ? "valid" : ""} ${
									digit.error ? "error" : ""
								}`}
								onChange={(e) =>
									this.handleDigitInput(e, index)
								}
								onKeyDown={(e) => this.handleKeyDown(e, index)}
								onFocus={(e) => this.handleFocus(e, index)}
								onBlur={() => this.handleBlur(index)}
								onPaste={(e) => this.handlePaste(e, index)}
								onClick={() => this.handleClick(index)}
								onContextMenu={(e) => e.preventDefault()}
								onDrop={(e) => e.preventDefault()}
								onDragOver={(e) => e.preventDefault()}
							/>
						))}
					</div>

					{this.state.blikError && (
						<div className="simplyin-blik-error">
							{this.state.blikError}
						</div>
					)}
				</div>
			</div>
		);
	}

	private handleKeyDown = (
		event: React.KeyboardEvent<HTMLInputElement>,
		index: number,
	): void => {
		const key = event.key;

		if (key === "Backspace" || key === "Delete") {
			if (
				this.state.digits[index].value === "" &&
				key === "Backspace" &&
				index > 0
			) {
				event.preventDefault();
				this.clearDigit(index - 1);
				this.focusInput(index - 1);
			} else if (this.state.digits[index].value !== "") {
				event.preventDefault();
				this.clearDigit(index);
			}
			return;
		}

		if (key === "ArrowLeft" && index > 0) {
			event.preventDefault();
			this.focusInput(index - 1);
			return;
		}

		if (key === "ArrowRight" && index < 5) {
			event.preventDefault();
			this.focusInput(index + 1);
			return;
		}

		if (/^[0-9]$/.test(key)) {
			event.preventDefault();
			this.setDigit(index, key);
			if (index < 5) {
				setTimeout(() => this.focusInput(index + 1), 5);
			}
			return;
		}

		const allowedKeys = ["Tab", "Enter", "Escape"];
		if (!allowedKeys.includes(key) && !event.ctrlKey && !event.metaKey) {
			event.preventDefault();
			event.stopPropagation();
		}
	};

	private handleDigitInput = (
		event: React.ChangeEvent<HTMLInputElement>,
		index: number,
	): void => {
		this.selectBlikRadioButton();

		let value = event.target.value;

		value = value.replace(/[^0-9]/g, "");

		if (value.length > 1) {
			value = value.charAt(value.length - 1);
		}

		if (value !== "") {
			this.setDigit(index, value);
			if (index < 5) {
				setTimeout(() => this.focusInput(index + 1), 5);
			}
		} else {
			this.clearDigit(index);
		}
	};

	private handleFocus = (
		event: React.FocusEvent<HTMLInputElement>,
		index: number,
	): void => {
		this.setState({ focusedIndex: index });
		this.clearError();

		this.selectBlikRadioButton();
		this.props.onFocus();

		setTimeout(() => {
			event.target.select();
		}, 5);
	};

	private handleBlur = (index: number): void => {
		setTimeout(() => {
			const container = this.inputRefs[0].current?.closest(
				".simplyin-blik-field-container",
			);
			if (container && !container.contains(document.activeElement)) {
				this.validateAllDigits();
			}
		}, 100);
	};

	private handlePaste = (
		event: React.ClipboardEvent<HTMLInputElement>,
		currentIndex: number,
	): void => {
		event.preventDefault();

		const paste = event.clipboardData.getData("text");
		const digits = paste.replace(/[^0-9]/g, "").substring(0, 6);

		if (digits.length > 0) {
			this.clearAllDigits();

			for (let i = 0; i < Math.min(digits.length, 6); i++) {
				this.setDigit(i, digits[i]);
			}

			const nextIndex = Math.min(digits.length, 5);
			this.focusInput(nextIndex);
		}
	};

	private handleClick = (index: number): void => {
		this.selectBlikRadioButton();
		this.props.onFocus();
	};

	private setDigit = (index: number, value: string): void => {
		const newDigits = [...this.state.digits];
		newDigits[index] = {
			value,
			filled: true,
			valid: false,
			error: false,
		};

		this.setState({ digits: newDigits }, () => {
			this.updateBlikValidation();
		});
	};

	private clearDigit = (index: number): void => {
		const newDigits = [...this.state.digits];
		newDigits[index] = {
			value: "",
			filled: false,
			valid: false,
			error: false,
		};

		this.setState({ digits: newDigits }, () => {
			this.updateBlikValidation();
		});
	};

	private clearAllDigits = (): void => {
		const newDigits = Array(6)
			.fill(null)
			.map(() => ({
				value: "",
				filled: false,
				valid: false,
				error: false,
			}));

		this.setState(
			{
				digits: newDigits,
				blikError: "",
				isComplete: false,
			},
			() => {
				this.updateBlikValidation();
				SimplyinPaymentMethod.setBlikCode("");
			},
		);
	};

	private focusInput = (index: number): void => {
		if (this.inputRefs[index]?.current) {
			this.inputRefs[index].current!.focus();
		}
	};

	private updateBlikValidation = (): void => {
		const values = this.state.digits.map((digit) => digit.value);
		const filledCount = values.filter((v) => /^[0-9]$/.test(v)).length;
		const blikCode = values.join("");

		const isComplete = filledCount === 6;

		if (isComplete) {
			const newDigits = this.state.digits.map((digit) => ({
				...digit,
				valid: /^[0-9]$/.test(digit.value),
				error: false,
			}));

			this.setState({
				digits: newDigits,
				blikCode,
				blikError: "",
				isComplete: true,
			});

			this.props.onBlikCodeChange(blikCode);
			SimplyinPaymentMethod.setBlikCode(blikCode);

			if (this.isSimplyInSelected()) {
				this.checkAndEnableButton(blikCode, true);
			}
		} else {
			const newDigits = this.state.digits.map((digit) => ({
				...digit,
				valid: false,
			}));

			this.setState({
				digits: newDigits,
				blikCode: "",
				isComplete: false,
			});

			SimplyinPaymentMethod.setBlikCode("");

			if (this.isSimplyInSelected()) {
				this.disablePaymentButton();
			}
		}
	};

	private validateAllDigits = (): boolean => {
		const values = this.state.digits.map((digit) => digit.value);
		const validDigits = values.filter((v) => /^[0-9]$/.test(v));

		if (validDigits.length === 0) {
			this.clearError();
			if (this.isSimplyInSelected()) {
				this.disablePaymentButton();
			}
			return true;
		}

		if (validDigits.length === 6) {
			const newDigits = this.state.digits.map((digit) => ({
				...digit,
				valid: /^[0-9]$/.test(digit.value),
				error: false,
			}));

			this.setState({
				digits: newDigits,
				blikError: "",
			});

			if (this.isSimplyInSelected()) {
				this.checkAndEnableButton();
			}
			return true;
		} else {
			const newDigits = this.state.digits.map((digit) => ({
				...digit,
				error: digit.value !== "",
				valid: false,
			}));

			this.setState({
				digits: newDigits,
				blikError: MessagesService.getMessage(
					"blik_code_is_invalid",
					"BLIK code is invalid.",
				),
			});

			if (this.isSimplyInSelected()) {
				this.disablePaymentButton();
			}
			return false;
		}
	};

	private clearError = (): void => {
		this.setState({ blikError: "" });
	};

	public getBlikCode = (): string => {
		return this.state.isComplete ? this.state.blikCode : "";
	};

	public isValid = (): boolean => {
		return this.state.isComplete;
	};

	public validate = (): boolean => {
		const result = this.validateAllDigits();

		if (result && this.isSimplyInSelected() && this.state.isComplete) {
			this.checkAndEnableButton();
		} else if (this.isSimplyInSelected()) {
			this.disablePaymentButton();
		}

		return result;
	};

	private enablePaymentButton(): void {
		const placeOrderButton = document.querySelector(
			".wc-block-components-checkout-place-order-button",
		) as HTMLButtonElement;
		if (placeOrderButton) {
			placeOrderButton.disabled = false;
		}
	}

	private disablePaymentButton(): void {
		const placeOrderButton = document.querySelector(
			".wc-block-components-checkout-place-order-button",
		) as HTMLButtonElement;
		if (placeOrderButton) {
			placeOrderButton.disabled = true;
		}
	}

	private selectBlikRadioButton = (): void => {
		const blikContainer =
			this.inputRefs[0].current?.closest(".simplyin-blik");
		const blikRadio = blikContainer?.querySelector(
			'input[type="radio"]',
		) as HTMLInputElement;

		if (blikRadio && !blikRadio.checked) {
			blikRadio.checked = true;

			blikRadio.dispatchEvent(new Event("change", { bubbles: true }));

			this.props.paymentChannel.handleToggleSelected();
		}
	};

	private isSimplyInSelected = (): boolean => {
		const simplyInRadio = document.querySelector(
			'input[name="radio-control-wc-payment-method-options"][value="simplyin"]',
		) as HTMLInputElement;
		return simplyInRadio && simplyInRadio.checked;
	};

	private checkAndEnableButton = (
		overrideBlikCode?: string,
		overrideIsComplete?: boolean,
	): void => {
		let isPhoneValid = window.SimplyIn?.validatePhoneNumber?.() || false;
		const phoneCheckbox = document.querySelector(
			"#simply-save-checkbox",
		) as HTMLInputElement;

		if (!phoneCheckbox || !phoneCheckbox.checked) {
			isPhoneValid = true;
		}

		const blikCode =
			overrideBlikCode !== undefined
				? overrideBlikCode
				: this.state.blikCode;
		const isComplete =
			overrideIsComplete !== undefined
				? overrideIsComplete
				: this.state.isComplete;
		const isBlikValid = isComplete && blikCode.length === 6;

		if (isBlikValid && isPhoneValid) {
			this.enablePaymentButton();
		} else {
			this.disablePaymentButton();
		}
	};
}
