import {registerPaymentMethod} from "@woocommerce/blocks-registry";
import {decodeEntities} from "@wordpress/html-entities";
import {getPaymentMethodData, getSetting} from "@woocommerce/settings";
import React from "react";
import {Renderer} from "./renderer";
import {PaymentMethodHeader} from "./components/PaymentMethodHeader";
import {
	PaymentMethodDataFactory
} from "./types/factories/PaymentMethodDataFactory";
import {PaymentMethodData} from "./types/models/PaymentMethodData";
import {MessagesService} from "./MessagesService";

const data = getPaymentMethodData("simplyin", {});

export class SimplyinPaymentMethod extends React.Component<
	Record<string, any>,
	{}
> {
	private static paymentMethodDataFromServer: PaymentMethodData;
	private static paymentOptionId: string;
	private static isBlik: boolean;
	private static blikCode: string;
	private static isAddCard: boolean;
	private static isCard: boolean;
	private static cardTokenData: any;

	public payment_data = ["test"];

	constructor() {
		super({});
	}

	public static getSelectedPaymentMethod(): string | null {
		const checkedRadio = document.querySelector(
			'.simplyin-block-payment input[type="radio"]:checked',
		) as HTMLInputElement;
		return checkedRadio ? checkedRadio.value : null;
	}

	public static validateBlikCode(): boolean {
		const selectedRadio = document.querySelector(
			'.simplyin-block-payment input[type="radio"]:checked',
		) as HTMLInputElement;

		if (!selectedRadio) return true;

		const paymentItem = selectedRadio.closest(
			".simplyin-block-payment-item",
		);

		if (!paymentItem || !paymentItem.classList.contains("simplyin-blik")) {
			return true;
		}

		const blikContainer = paymentItem.querySelector(
			".simplyin-blik-field-container",
		);
		if (!blikContainer) return true;

		const blikInputs = blikContainer.querySelectorAll("input");
		const blikCode = Array.from(blikInputs)
			.map((input) => input.value)
			.join("");

		return /^[0-9]{6}$/.test(blikCode);
	}

	public static isMainPaymentMethodSelected(): boolean {
		const simplyInRadio = document.querySelector(
			'input[name="radio-control-wc-payment-method-options"][value="simplyin"]',
		) as HTMLInputElement;
		return simplyInRadio ? simplyInRadio.checked : false;
	}

	public static init(paymentMethodData: []) {
		SimplyinPaymentMethod.paymentMethodDataFromServer =
			PaymentMethodDataFactory.create(data);
		MessagesService.setMessages(
			SimplyinPaymentMethod.paymentMethodDataFromServer.messages,
		);
		registerPaymentMethod({
			name: "simplyin",
			label: (
				<PaymentMethodHeader
					label={this.paymentMethodDataFromServer.label}
					iconSrc={this.paymentMethodDataFromServer.iconSrc}
					iconAlt={this.paymentMethodDataFromServer.label}
					providerLogoSrc={data?.payment_provider?.logo_url}
				/>
			),
			content: <SimplyinPaymentMethod/>,
			edit: <SimplyinPaymentMethod/>,
			ariaLabel: this.paymentMethodDataFromServer.label,
			supports: {
				features: this.paymentMethodDataFromServer.supports,
			},
			canMakePayment: () => {
				return true;
			},
			placeOrderButtonLabel:
			this.paymentMethodDataFromServer.placeOrderButtonLabel,
			savedTokenComponent: <SimplyinPaymentMethod/>,
		});
	}

	public static setPaymentChannelId(id: string) {
		SimplyinPaymentMethod.paymentOptionId = id;
	}

	public static setIsBlik(isBlik: boolean) {
		SimplyinPaymentMethod.isBlik = isBlik;
	}

	public static setBlikCode(blikCode: string) {
		SimplyinPaymentMethod.blikCode = blikCode;
	}

	public static setIsAddCard(isAddCard: boolean) {
		SimplyinPaymentMethod.isAddCard = isAddCard;
	}

	public static setIsCard(isCard: boolean) {
		SimplyinPaymentMethod.isCard = isCard;
	}

	public static setCardTokenData(cardTokenData: any) {
		SimplyinPaymentMethod.cardTokenData = cardTokenData;
	}

	public static getCardTokenData() {
		return SimplyinPaymentMethod.cardTokenData;
	}

	public static checkButtonState(): void {
		const instances = document.querySelectorAll(
			"[data-simplyin-payment-method]",
		);
		if (instances.length > 0) {
			const firstInstance = (instances[0] as any).__reactInternalInstance;
			if (firstInstance) {
				const component =
					firstInstance.memoizedProps?._owner?.stateNode;
				if (component && component.checkAndEnableButton) {
					component.checkAndEnableButton();
				}
			}
		}
	}

	render() {
		return (
			<>
				<Renderer/>
			</>
		);
	}

	componentDidMount() {
		const {eventRegistration, emitResponse} = this.props;
		const {onPaymentProcessing, onCheckoutSuccess} = eventRegistration;

		this.unsubscribe = onPaymentProcessing(async () => {
			const simplyinPaymentOptionId =
				SimplyinPaymentMethod.paymentOptionId;
			const customDataIsValid = !!simplyinPaymentOptionId;

			if (customDataIsValid) {
				const isBlik = SimplyinPaymentMethod.isBlik;
				const blikCode = SimplyinPaymentMethod.blikCode;
				const isAddCard = SimplyinPaymentMethod.isAddCard;
				const isCard = SimplyinPaymentMethod.isCard;
				const cardTokenData = SimplyinPaymentMethod.cardTokenData;
				const nonce = SimplyinPaymentMethod.paymentMethodDataFromServer.nonce;

				if (isBlik) {
					return {
						type: emitResponse.responseTypes.SUCCESS,
						meta: {
							paymentMethodData: {
								simplyin_payment_option_id:
								simplyinPaymentOptionId,
								simplyin_blik_code: blikCode,
								payment_on_block_checkout: "1",
								simplyin_blocks_token: nonce,

							},
							simplyin_blocks_token: SimplyinPaymentMethod.paymentMethodDataFromServer.nonce
						},
					};
				} else if (isAddCard) {
					const waitForCardTokenData = async (
						attempts = 4,
					): Promise<any> => {
						for (let i = 0; i < attempts; i++) {
							const currentCardTokenData =
								SimplyinPaymentMethod.cardTokenData;
							if (currentCardTokenData) {
								return currentCardTokenData;
							}
							if (i < attempts - 1) {
								await new Promise((resolve) =>
									setTimeout(resolve, 500),
								);
							}
						}
						return null;
					};

					const finalCardTokenData = await waitForCardTokenData();

					if (!finalCardTokenData) {
						return {
							type: emitResponse.responseTypes.ERROR,
							message: MessagesService.getMessage(
								"card_token_not_ready",
								"Card token data is not ready yet.",
							),
						};
					}

					return {
						type: emitResponse.responseTypes.SUCCESS,
						meta: {
							paymentMethodData: {
								simplyin_payment_option_id:
								simplyinPaymentOptionId,
								simplyin_ott:
									finalCardTokenData.oneTimeToken || "",
								simplyin_first_digits:
									finalCardTokenData.first6digits || "",
								simplyin_last_digits:
									finalCardTokenData.last4digits || "",
								simplyin_organization:
									finalCardTokenData.organization || "",
								simplyin_card_name:
									finalCardTokenData.cardName || "",
								simplyin_card_save_checkbox:
									finalCardTokenData.saveCard
										? "true"
										: "false",
								add_card_block_payment: "1",
								simplyin_blocks_token: SimplyinPaymentMethod.paymentMethodDataFromServer.nonce
							},
						},
					};
				} else if (isCard) {
					return {
						type: emitResponse.responseTypes.SUCCESS,
						meta: {
							paymentMethodData: {
								simplyin_payment_option_id:
								simplyinPaymentOptionId,
								saved_card_payment: "1",
								simplyin_blocks_token: SimplyinPaymentMethod.paymentMethodDataFromServer.nonce
							},
						},
					};
				} else {
					return {
						type: emitResponse.responseTypes.SUCCESS,
						meta: {
							paymentMethodData: {
								simplyin_payment_option_id:
								simplyinPaymentOptionId,
								simplyin_blocks_token: SimplyinPaymentMethod.paymentMethodDataFromServer.nonce
							},
						},
					};
				}
			}

			return {
				type: emitResponse.responseTypes.ERROR,
				message: MessagesService.getMessage(
					"no_payment_selected",
					"No payment channel selected.",
				),
			};
		});

		this.setupPaymentMethodListener();
	}

	private setupPaymentMethodListener() {
		const paymentMethodRadio = document.querySelector(
			'input[name="radio-control-wc-payment-method-options"][value="simplyin"]',
		);

		if (paymentMethodRadio) {
			if ((paymentMethodRadio as HTMLInputElement).checked) {
				this.handleSimplyInSelected();
			}

			document.addEventListener("change", (event) => {
				const target = event.target as HTMLInputElement;
				if (target.name === "radio-control-wc-payment-method-options") {
					if (target.value === "simplyin" && target.checked) {
						this.handleSimplyInSelected();
					} else {
						this.handleSimplyInDeselected();
					}
				}
			});
		}
	}

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

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

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

		if (!isSimplyInSelected) {
			this.enablePaymentButton();
			return;
		}

		const selectedPaymentOption = this.getSelectedPaymentOption();

		if (!selectedPaymentOption) {
			this.disablePaymentButton();
			return;
		}

		this.delegateToSelectedPaymentMethod();
	};

	private getSelectedPaymentOption = (): Element | null => {
		const paymentRadios = document.querySelectorAll(
			'.simplyin-block-payment input[type="radio"]:checked',
		);

		return paymentRadios.length > 0 ? paymentRadios[0] : null;
	};

	private delegateToSelectedPaymentMethod = (): void => {
		const selectedRadio =
			this.getSelectedPaymentOption() as HTMLInputElement;
		if (!selectedRadio) {
			this.disablePaymentButton();
			return;
		}

		const paymentItem = selectedRadio.closest(
			".simplyin-block-payment-item",
		);
		if (!paymentItem) {
			this.enablePaymentButton();
			return;
		}

		if (paymentItem.classList.contains("simplyin-blik")) {
			const blikContainer = paymentItem.querySelector(
				".simplyin-blik-field-container",
			);
			if (blikContainer) {
				const blikInputs = blikContainer.querySelectorAll("input");
				const blikCode = Array.from(blikInputs)
					.map((input) => input.value)
					.join("");
				const isBlikValid =
					blikCode.length === 6 && /^\d{6}$/.test(blikCode);
				let isPhoneValid =
					window.SimplyIn?.validatePhoneNumber?.() || false;
				const phoneCheckbox = document.querySelector(
					"#simply-save-checkbox",
				) as HTMLInputElement;

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

				if (isBlikValid && isPhoneValid) {
					this.enablePaymentButton();
				} else {
					this.disablePaymentButton();
				}
			} else {
				this.disablePaymentButton();
			}
		} else if (paymentItem.classList.contains("simplyin-add-card")) {
			this.enablePaymentButton();
		} else if (paymentItem.classList.contains("simplyin-card")) {
			this.enablePaymentButton();
		} else {
			this.enablePaymentButton();
		}
	};

	private handleSimplyInSelected() {
		setTimeout(() => {
			this.checkAndEnableButton();
			this.setupInternalPaymentMethodListener();
			this.setupPaymentOptionChangeObserver();
		}, 100);
	}

	private handleSimplyInDeselected() {
		let isPhoneValid = window.SimplyIn?.validatePhoneNumber?.() || false;
		const phoneCheckbox = document.querySelector(
			"#simply-save-checkbox",
		) as HTMLInputElement;

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

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

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

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

	private setupInternalPaymentMethodListener() {
		const paymentContainer = document.querySelector(
			".simplyin-block-payment",
		);
		if (!paymentContainer) return;

		const paymentRadios = paymentContainer.querySelectorAll(
			'input[type="radio"]',
		);

		paymentRadios.forEach((radio) => {
			radio.addEventListener("change", () => {
				this.checkAndEnableButton();
			});
		});
	}

	private setupPaymentOptionChangeObserver() {
		const observer = new MutationObserver(() => {
			setTimeout(() => {
				this.checkAndEnableButton();
			}, 50);
		});

		const paymentContainer = document.querySelector(
			".simplyin-block-payment",
		);
		if (paymentContainer) {
			observer.observe(paymentContainer, {
				childList: true,
				subtree: true,
				attributes: true,
				attributeFilter: ["class"],
			});
		}
	}

	componentWillUnmount() {
		if (this.unsubscribe) {
			this.unsubscribe();
		}
	}
}

SimplyinPaymentMethod.init(data);

declare global {
	interface Window {
		SimplyinGetSelectedPaymentMethod: () => string | null;
		SimplyinValidateBlikCode: () => boolean;
		SimplyinIsMainPaymentMethodSelected: () => boolean;
	}
}

window.SimplyinGetSelectedPaymentMethod = () =>
	SimplyinPaymentMethod.getSelectedPaymentMethod();
window.SimplyinValidateBlikCode = () =>
	SimplyinPaymentMethod.validateBlikCode();
window.SimplyinIsMainPaymentMethodSelected = () =>
	SimplyinPaymentMethod.isMainPaymentMethodSelected();
