var SNAPIHelper = {}
var snAPIHelper = {}

snAPIHelper.common = new class {
    executeInFrames(script) {
        var frames = document.getElementsByTagName("iframe");
        var message = {name: "exec", message: { script: script }};

        for (var index = 0; index < frames.length; index++) {
            frames[index].contentWindow.postMessage(message, "*");
        }
    }
}

// Message listener for relaying callbacks/events to iFrames
window.addEventListener('message', function(e) {
    console.log("Test", e);
    if (typeof e.data === "object") {
        if (e.data.name == "exec") {
            eval(e.data.message.script);
        }
    }
}, false);


// MARK: -
var com_bzg_unite_del_key_disable = true;

SafariRemoteNotification = class {
    
}

window.oldNotification = window.Notification;

window.Notification = function() {
    let webwhatsappWorkaroundURL = document.URL;
    if (webwhatsappWorkaroundURL.includes("https://web.whatsapp.com")) {
        //webwhatsappWorkaround
        window.webkit.messageHandlers.note.postMessage([JSON.stringify(arguments[0]), JSON.stringify(arguments[1])]);
    } else {
        window.webkit.messageHandlers.notifications.postMessage([arguments[0], arguments[1]]);
        const notificationEnabled = true;
        return notificationEnabled ? new window.oldNotification(...arguments) : {};
    }
};

Object.defineProperty(Notification, 'permission', {
    get() {
        return 'granted';
    }
});

Notification.requestPermission = (callback) => {
    if (typeof callback === 'function') {
        callback('granted');
    } else {
        return Promise.resolve(Notification.permission);
    }
};

window.safari = {}
window.safari.pushNotification = new SafariRemoteNotification();

// MARK: -

snAPIHelper.autoFill = new class {
	constructor() {
		window.addEventListener('DOMContentLoaded', function() {
			var style = document.createElement('style');
			style.innerHTML = '\
			.SNAutofill {\
				background-color: #ffffdd !important;\
			}\
			';
			document.head.appendChild(style);
		}, false);
		
		this.KEYCODE_ARROW_DOWN = 40;
		this.lastDomUpdateTime = 0;
		this.domUpdatePending = false;
		this.THROTTLE_DELAY = 250; // ms
	}
	
	autoFill(username, password) {
		if (typeof this.loginFields !== "undefined") {
			if (this.loginFields["username"]) {
				this.loginFields["username"].value = username;
				this.dispatchKeyboardEvent(this.loginFields["username"], "keydown", this.KEYCODE_ARROW_DOWN);
				this.dispatchKeyboardEvent(this.loginFields["username"], "keyup", this.KEYCODE_ARROW_DOWN);
				this.loginFields["username"].classList.add("SNAutofill");
			}

			if (this.loginFields["password"]) {
				this.loginFields["password"].value = password;
				this.dispatchKeyboardEvent(this.loginFields["password"], "keydown", this.KEYCODE_ARROW_DOWN);
				this.dispatchKeyboardEvent(this.loginFields["password"], "keyup", this.KEYCODE_ARROW_DOWN);
				this.loginFields["password"].classList.add("SNAutofill");
			}
		}
		snAPIHelper.common.executeInFrames("snAPIHelper.autoFill.autoFill('"+username+"', '"+password+"')");
	}
	
	domUpdatedThrottled() {
		const now = Date.now();
		
		// Throttle updates to reduce CPU usage
		if (this.domUpdatePending || (now - this.lastDomUpdateTime) < this.THROTTLE_DELAY) {
			if (!this.domUpdatePending) {
				this.domUpdatePending = true;
				setTimeout(() => {
					this.domUpdatePending = false;
					this.lastDomUpdateTime = Date.now();
					this.domUpdated();
				}, this.THROTTLE_DELAY);
			}
			return;
		}
		
		this.lastDomUpdateTime = now;
		this.domUpdated();
	}
	
	domUpdated() {
		var loginFields = this.getLoginFields();
		if (typeof loginFields !== "undefined") {
			// Prevent re‑processing the same password element again.
			if (typeof this.loginFields !== "undefined") {
				var samePassword = (loginFields["password"] && this.loginFields["password"] && loginFields["password"] === this.loginFields["password"]);
				var sameUsername = (loginFields["username"] && this.loginFields["username"] && loginFields["username"] === this.loginFields["username"]);
				if (samePassword && sameUsername) {
					return;
				}
			}

			var usernameValue = (loginFields["username"] ? loginFields["username"].value : "");
			var passwordValue = (loginFields["password"] ? loginFields["password"].value : "");
			window.webkit.messageHandlers.autoFill.postMessage(["onLoginFound", { "username": usernameValue, "password": passwordValue }]);

			if (loginFields["username"]) {
				loginFields["username"].addEventListener('input', this.onUsernameChange, false);
				loginFields["username"].addEventListener("focus", this.onUsernameFocused, false);
				loginFields["username"].addEventListener("blur", this.onUsernameBlurred, false);
				loginFields["username"].addEventListener("keyup", this.onKeyUp, false);
			}
			if (loginFields["password"]) {
				loginFields["password"].addEventListener('input', this.onPasswordChange, false);
				loginFields["password"].addEventListener("focus", this.onPasswordFocused, false);
				loginFields["password"].addEventListener("blur", this.onPasswordBlurred, false);
				loginFields["password"].addEventListener("keyup", this.onKeyUp, false);
			}
		}
		this.loginFields = loginFields;
	}
	
	getLoginFields() {
		// First, try to locate conventional username‑password pairs (same logic as before)
		var passwordFields = this.allPasswordFields();
		var passwordLength = passwordFields.length;
		var loginGroups = [];
		while (passwordLength--) {
			var curPasswordField = passwordFields[passwordLength];
			var parentForm = this.parentForm(curPasswordField);

			var possibleUserField = null;
			if (parentForm) {
				possibleUserField = this.possibleUserField(parentForm, curPasswordField);
			} else {
				possibleUserField = this.possibleUserField(document, curPasswordField);
			}

			// It is possible that no explicit username field exists on the same page (e.g. multi‑step logins).
			// In that scenario, we still want to return the password field alone so that we can at least offer
			// password filling.
			if (possibleUserField) {
				loginGroups.push([possibleUserField, curPasswordField]);
			} else {
				loginGroups.push([null, curPasswordField]);
			}
		}

		if (loginGroups.length > 0) {
			// Prefer groups that have a visible username field; otherwise fall back to password‑only group.
			for (var i = 0; i < loginGroups.length; i++) {
				var u = loginGroups[i][0];
				var p = loginGroups[i][1];
				if (u && p && u.offsetParent !== null && p.offsetParent !== null) {
					return { "username": u, "password": p };
				}
			}
			// No visible username field – return the first password field we found.
			return { "username": null, "password": loginGroups[0][1] };
		}

                // Lastly, handle pages that only ask for username / email (first step of multi‑step flows).
                var inputs = document.querySelectorAll('input[type="text"], input[type="email"]');
                if (inputs.length > 0) {
                        // Pick the first visible input field that appears to be for login/authentication.
                        for (var i = 0; i < inputs.length; i++) {
                                if (inputs[i].offsetParent !== null) {
                                        var attrString = ((inputs[i].name || "") + (inputs[i].id || "") + (inputs[i].placeholder || "") + (inputs[i].getAttribute("aria-label") || "") + (inputs[i].className || "")).toLowerCase();
                                        
                                        // Exclude fields that are clearly not for login
                                        var isExcluded = attrString.indexOf("search") !== -1 || 
                                                        attrString.indexOf("query") !== -1 ||
                                                        attrString.indexOf("title") !== -1 ||
                                                        attrString.indexOf("subject") !== -1 ||
                                                        attrString.indexOf("recipient") !== -1 ||
                                                        attrString.indexOf("label") !== -1 ||
                                                        attrString.indexOf("tag") !== -1 ||
                                                        attrString.indexOf("compose") !== -1 ||
                                                        attrString.indexOf("to:") !== -1 ||
                                                        inputs[i].getAttribute("role") === "combobox" ||
                                                        inputs[i].getAttribute("role") === "searchbox" ||
                                                        inputs[i].hasAttribute("contenteditable");
                                        
                                        // Only consider fields that have login-related attributes
                                        var isLoginRelated = attrString.indexOf("user") !== -1 || 
                                                            attrString.indexOf("email") !== -1 || 
                                                            attrString.indexOf("login") !== -1 || 
                                                            attrString.indexOf("account") !== -1 ||
                                                            attrString.indexOf("signin") !== -1 ||
                                                            inputs[i].type.toLowerCase() === "email" ||
                                                            inputs[i].getAttribute("autocomplete") === "username" ||
                                                            inputs[i].getAttribute("autocomplete") === "email";
                                        
                                        if (!isExcluded && isLoginRelated) {
                                                return { "username": inputs[i], "password": null };
                                        }
                                }
                        }
                }
	}
	
	possibleUserField(parent, passwordField) {
		var inputFieldsByCategory = {};
		var inputs = parent.getElementsByTagName('input');
		var passwordFieldIndex = [].slice.call(inputs).indexOf(passwordField);
		var inputsByCategory = {};
		for (var i = 0; i < inputs.length; i++) {
			if (inputs[i] === passwordField || (passwordFieldIndex - i) < 0) {
				continue;
			}
			
			var fieldType = (inputs[i].hasAttribute("type") ?
							 inputs[i].getAttribute("type").toLowerCase() :
							 inputs[i].type);
			
			if (fieldType == "text"  ||
				fieldType == "email" ||
				fieldType == "url"   ||
				fieldType == "tel"   ||
				fieldType == "number") {
				if (typeof inputsByCategory[fieldType] === "undefined") {
					inputsByCategory[fieldType] = [];
				}
				
				inputsByCategory[fieldType].push([inputs[i], passwordFieldIndex - i]);
			}
		}
		
		if (typeof inputsByCategory["email"] !== "undefined") {
			return inputsByCategory["email"].sort(this.compare)[0][0];
		} else if (typeof inputsByCategory["text"] !== "undefined") {
			return inputsByCategory["text"].sort(this.compare)[0][0];
		}
	}
	
	allPasswordFields() {
		var inputs = document.getElementsByTagName('input');
		var	length = inputs.length;
		var	fields = [];
		while (length--) {
			if (inputs[length].type === 'password') {
				fields[fields.length] = inputs[length];
			}
		}
		return fields;
	}
	
	parentForm(element) {
		while (element.parentNode) {
			if (element.parentNode.nodeName.toLowerCase() === 'form') {
				return element.parentNode;
			}
			element = element.parentNode;
		}
	}
	
	compare(inputA, inputB) {
	  return (inputA[1] > inputB[1]);
	}
	
	onUsernameFocused(event) {
		if (snAPIHelper.autoFill.loginFields["username"].classList.contains("SNAutofill")) {
			return
		}
		var viewportOffset = event.target.getBoundingClientRect();
		window.webkit.messageHandlers.autoFill.postMessage(["onUsernameFocused", {"top": viewportOffset.bottom, "left": viewportOffset.left}]);
	}
	
	onUsernameBlurred(event) {
		window.webkit.messageHandlers.autoFill.postMessage(["onUsernameBlurred"]);
	}
	
	onPasswordFocused(event) {
		if (snAPIHelper.autoFill.loginFields["password"].classList.contains("SNAutofill") && snAPIHelper.autoFill.loginFields["password"].value.length != 0) {
			return
		}
		var viewportOffset = event.target.getBoundingClientRect();
		window.webkit.messageHandlers.autoFill.postMessage(["onPasswordFocused", {"top": viewportOffset.bottom, "left": viewportOffset.left}]);
	}
	
	onPasswordBlurred(event) {
		window.webkit.messageHandlers.autoFill.postMessage(["onPasswordBlurred"]);
	}
	
	onUsernameChange(event) {
		var viewportOffset = event.target.getBoundingClientRect();
		snAPIHelper.autoFill.loginFields["username"].classList.remove("SNAutofill");
		window.webkit.messageHandlers.autoFill.postMessage(["onUsernameChange", event.target.value, {"top": viewportOffset.bottom, "left": viewportOffset.left}]);
	}
	
	onPasswordChange(event) {
		var viewportOffset = event.target.getBoundingClientRect();
		snAPIHelper.autoFill.loginFields["password"].classList.remove("SNAutofill");
		window.webkit.messageHandlers.autoFill.postMessage(["onPasswordChange", event.target.value, {"top": viewportOffset.bottom, "left": viewportOffset.left}]);
	}
	
	onKeyUp(event) {
		if (event.keyCode === 13) {
			window.webkit.messageHandlers.autoFill.postMessage(["onKeyUp", 13]);
			event.preventDefault();
		} else if (event.keyCode === 27) {
			window.webkit.messageHandlers.autoFill.postMessage(["onKeyUp", 27]);
		} else if (event.key == "ArrowUp") {
			window.webkit.messageHandlers.autoFill.postMessage(["onKeyUp", -1]);
		} else if (event.key == "ArrowDown") {
			window.webkit.messageHandlers.autoFill.postMessage(["onKeyUp", 1]);
		}
	}
	
	dispatchKeyboardEvent(element, eventName, keyCode) {
	  var event = document.createEvent("KeyboardEvent");
	  event.initKeyboardEvent(eventName, true, true, window, 0, 0, 0, 0, 0, keyCode);
	  element.dispatchEvent(event);
	}
}

// Optimized DOM observer - only watch for relevant changes
snAPIHelper.observer = new MutationObserver(function(mutationsList, observer) {
	let shouldUpdate = false;
	
	for (let mutation of mutationsList) {
		// Only care about added nodes and specific attribute changes
		if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
			for (let node of mutation.addedNodes) {
				if (node.nodeType === Node.ELEMENT_NODE) {
					// Check if added node contains form inputs
					if (node.tagName === 'INPUT' || node.tagName === 'FORM' || 
						node.querySelector('input[type="password"], input[type="text"], input[type="email"]')) {
						shouldUpdate = true;
						break;
					}
				}
			}
		} else if (mutation.type === 'attributes' && 
				   mutation.target.tagName === 'INPUT' && 
				   (mutation.attributeName === 'type' || mutation.attributeName === 'name')) {
			shouldUpdate = true;
		}
		
		if (shouldUpdate) break;
	}
	
	if (shouldUpdate) {
		snAPIHelper.autoFill.domUpdatedThrottled();
	}
});

// Only observe specific changes that matter for form detection
snAPIHelper.observer.observe(document, { 
	childList: true, 
	subtree: true,
	attributes: true,
	attributeFilter: ['type', 'name'] // Only watch for type/name changes on inputs
});
