/* global window, document */
(function (window, document) {
	'use strict';

	const app = window.MailDoctorAdminApp;
	const API_CREATE_TRIGGER_SELECTOR = '[data-mail-doctor-api-create-submit]';

	if (!app) {
		return;
	}

	function setCopyState(trigger, state) {
		if (!trigger) {
			return;
		}

		if (state) {
			trigger.setAttribute('data-mail-doctor-copy-state', state);
		} else {
			trigger.removeAttribute('data-mail-doctor-copy-state');
		}

		trigger.classList.remove('is-copied', 'is-error');

		if ('success' === state) {
			trigger.classList.add('is-copied');
		} else if ('error' === state) {
			trigger.classList.add('is-error');
		}

		if (trigger._mdCopyTimer) {
			window.clearTimeout(trigger._mdCopyTimer);
		}

		if (state) {
			trigger._mdCopyTimer = window.setTimeout(() => {
				trigger.classList.remove('is-copied', 'is-error');
				trigger.removeAttribute('data-mail-doctor-copy-state');
				trigger._mdCopyTimer = null;
			}, 2000);
		}
	}

	function fallbackCopy(input, trigger) {
		if (!input) {
			setCopyState(trigger, 'error');
			return;
		}

		const rawValue = typeof input.value === 'string' ? input.value : input.textContent;
		const value = String(rawValue || '');

		if (!value) {
			setCopyState(trigger, 'error');
			return;
		}

		let success = false;
		const activeElement = document.activeElement;
		const canSelectInput = typeof input.select === 'function';
		const wasReadonly = input.hasAttribute && input.hasAttribute('readonly');

		if (canSelectInput) {
			if (wasReadonly) {
				input.removeAttribute('readonly');
			}

			if (typeof input.focus === 'function') {
				try {
					input.focus({ preventScroll: true });
				} catch (error) {
					input.focus();
				}
			}
			input.select();
			if (typeof input.setSelectionRange === 'function') {
				input.setSelectionRange(0, value.length);
			}

			try {
				success = document.execCommand('copy');
			} catch (error) {
				success = false;
			}

			if (wasReadonly) {
				input.setAttribute('readonly', 'readonly');
			}

			input.blur();
		}

		if (!success) {
			const helper = document.createElement('textarea');
			helper.value = value;
			helper.setAttribute('readonly', 'readonly');
			helper.style.position = 'absolute';
			helper.style.opacity = '0';
			helper.style.pointerEvents = 'none';
			helper.style.left = '-9999px';
			helper.style.top = `${window.pageYOffset || 0}px`;
			document.body.appendChild(helper);

			helper.select();
			if (typeof helper.setSelectionRange === 'function') {
				helper.setSelectionRange(0, value.length);
			}

			try {
				success = document.execCommand('copy');
			} catch (error) {
				success = false;
			}

			document.body.removeChild(helper);
		}

		if (activeElement && typeof activeElement.focus === 'function') {
			activeElement.focus();
		}

		setCopyState(trigger, success ? 'success' : 'error');
	}

	function copyFromSelector(selector, trigger) {
		if (!selector) {
			return;
		}

		const input = document.querySelector(selector);

		if (!input) {
			return;
		}

		const value = typeof input.value === 'string' ? input.value : input.textContent;

		if (!value) {
			return;
		}

		if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
			navigator.clipboard
				.writeText(value)
				.then(() => {
					setCopyState(trigger, 'success');
				})
				.catch(() => {
					fallbackCopy(input, trigger);
				});

			return;
		}

		fallbackCopy(input, trigger);
	}

	function handleRegenerate(trigger) {
		if (!trigger) {
			return;
		}

		const confirmMessage = trigger.getAttribute('data-mail-doctor-confirm');

		if (confirmMessage && !window.confirm(confirmMessage)) {
			return;
		}

		const flag = document.getElementById('mail-doctor-webhook-regenerate');
		const tokenField = document.getElementById('mail-doctor-webhook-token');
		const pendingLabel = trigger.getAttribute('data-mail-doctor-pending') || '';

		if (flag) {
			flag.value = '1';
		}

		if (tokenField) {
			if (pendingLabel) {
				tokenField.value = '';
				tokenField.setAttribute('placeholder', pendingLabel);
			}

			tokenField.value = tokenField.value || '';
			tokenField.setAttribute('data-mail-doctor-secret-pending', 'true');
		}

		trigger.classList.add('is-pending');
		trigger.setAttribute('disabled', 'disabled');
	}

	function safeJSONParse(rawValue, fallback) {
		if (!rawValue || typeof rawValue !== 'string') {
			return fallback;
		}

		try {
			return JSON.parse(rawValue);
		} catch (error) {
			return fallback;
		}
	}

	function escapeHTML(value) {
		if (value === null || value === undefined) {
			return '';
		}

		return String(value)
			.replace(/&/g, '&amp;')
			.replace(/</g, '&lt;')
			.replace(/>/g, '&gt;')
			.replace(/"/g, '&quot;')
			.replace(/'/g, '&#39;');
	}

	function initApiKeys(appInstance) {
		const container = document.querySelector('[data-mail-doctor-api-keys]');

		if (!container) {
			return;
		}

		const ajaxUrl = (appInstance && appInstance.ajaxUrl) || '';

		if (!ajaxUrl) {
			return;
		}

		const nonces = (appInstance && appInstance.nonces && appInstance.nonces.apiKeys) || {};
		const i18n = (appInstance && appInstance.i18n) || {};
		const initialKeys = safeJSONParse(
			container.getAttribute('data-mail-doctor-api-keys') || container.getAttribute('data-mail-doctor-api-keys-initial'),
			[]
		);

		const state = {
			keys: Array.isArray(initialKeys) ? initialKeys.slice() : [],
		};

		const listBody = container.querySelector('[data-mail-doctor-api-keys-list]');
		const emptyState = container.querySelector('[data-mail-doctor-api-keys-empty]');
		const noticeBox = container.querySelector('[data-mail-doctor-api-notice]');
		const createForm = container.querySelector('[data-mail-doctor-api-create]');
		const submitButton =
			(createForm && createForm.querySelector(API_CREATE_TRIGGER_SELECTOR)) ||
			container.querySelector(API_CREATE_TRIGGER_SELECTOR);
		const secretBox = container.querySelector('[data-mail-doctor-api-secret]');
		const secretField = container.querySelector('[data-mail-doctor-api-secret-field]');
		const secretLabel = container.querySelector('[data-mail-doctor-api-secret-label]');
		const scopeInputs = Array.prototype.slice.call(container.querySelectorAll('[data-mail-doctor-api-scope]'));
		const isFormElement =
			createForm &&
			typeof window.HTMLFormElement !== 'undefined' &&
			createForm instanceof window.HTMLFormElement;
		const defaultButtonText = submitButton ? submitButton.textContent : '';
		const hasURLSearchParams = typeof window.URLSearchParams === 'function';

		function isURLSearchParams(value) {
			return hasURLSearchParams && value instanceof window.URLSearchParams;
		}

		function createPayload() {
			if (hasURLSearchParams) {
				return new window.URLSearchParams();
			}

			return new window.FormData();
		}

		function appendPayload(target, key, value) {
			if (!target || !key) {
				return;
			}

			if (isURLSearchParams(target)) {
				target.append(key, value);
				return;
			}

			target.append(key, value);
		}

		function resetCreateControls() {
			if (!createForm) {
				return;
			}

			const controls = Array.prototype.slice.call(createForm.querySelectorAll('input, select, textarea'));
			controls.forEach((control) => {
				if (!control) {
					return;
				}

				const nodeName = control.nodeName ? control.nodeName.toLowerCase() : '';

				if ('input' === nodeName) {
					const type = (control.getAttribute('type') || '').toLowerCase();

					if ('checkbox' === type || 'radio' === type) {
						control.checked = Boolean(control.defaultChecked);
						return;
					}

					if ('button' === type || 'submit' === type) {
						return;
					}

					control.value = control.defaultValue || '';
					return;
				}

				if ('textarea' === nodeName || 'select' === nodeName) {
					control.value = control.defaultValue || '';
				}
			});
		}

		function updateDataset() {
			try {
				container.setAttribute('data-mail-doctor-api-keys', JSON.stringify(state.keys));
			} catch (error) {
				// Ignore JSON stringify errors silently.
			}
		}

		function showNotice(type, message) {
			if (!noticeBox) {
				return;
			}

			const text = message || '';
			noticeBox.textContent = text;
			noticeBox.hidden = !text;

			noticeBox.classList.remove('notice-success', 'notice-error');

			if ('error' === type) {
				noticeBox.classList.add('notice-error');
			} else {
				noticeBox.classList.add('notice-success');
			}
		}

		function clearNotice() {
			showNotice('success', '');
		}

		function renderRow(key) {
			if (!key || typeof key !== 'object') {
				return '';
			}

			const id = escapeHTML(key.id || '');
			const displayId = escapeHTML(key.display_id || key.displayId || '') || id;
			const status = escapeHTML(key.status || 'active');
			const statusLabel = escapeHTML(key.status_label || (status === 'revoked' ? (i18n.apiKeyRevoked || 'Revoked') : (i18n.apiKeyStatusActive || 'Active')));
			const label = escapeHTML(key.label || '');
			const createdDisplay = escapeHTML(key.created_at_display || '');
			const createdIso = escapeHTML(key.created_at_iso || '');
			const createdRelative = escapeHTML(key.created_at_relative || '');
			const lastDisplay = escapeHTML(key.last_used_display || '');
			const lastIso = escapeHTML(key.last_used_iso || '');
			const lastRelative = escapeHTML(key.last_used_relative || '');
			const lastFallback = escapeHTML(key.last_used_fallback || i18n.apiKeyNeverUsed || 'Never used');
			const lastIpRaw = key.last_ip || '';
			const canRevoke = Boolean(key.can_revoke);

			let scopesHtml = '';
			if (Array.isArray(key.scopes_display) && key.scopes_display.length) {
				scopesHtml = key.scopes_display
					.map((scopeLabel) => `<span class="mail-doctor-api-keys__badge">${escapeHTML(scopeLabel)}</span>`)
					.join('');
			} else {
				scopesHtml = `<span class="mail-doctor-api-keys__muted">${escapeHTML(i18n.apiKeyNoScopes || '—')}</span>`;
			}

			let createdColumn = '<span class="mail-doctor-api-keys__muted">&mdash;</span>';
			if (createdDisplay) {
				createdColumn = `<time datetime="${createdIso}">${createdDisplay}</time>`;
				if (createdRelative) {
					createdColumn += `<div class="mail-doctor-api-keys__muted">${createdRelative}</div>`;
				}
			}

			let lastColumn = `<span class="mail-doctor-api-keys__muted">${lastFallback}</span>`;
			if (lastDisplay) {
				lastColumn = `<time datetime="${lastIso}">${lastDisplay}</time>`;
				if (lastRelative) {
					lastColumn += `<div class="mail-doctor-api-keys__muted">${lastRelative}</div>`;
				}
			}

			if (lastIpRaw) {
				const formattedIp = i18n.apiKeyLastIp ? i18n.apiKeyLastIp.replace('%s', String(lastIpRaw)) : `Last IP: ${escapeHTML(lastIpRaw)}`;
				lastColumn += `<div class="mail-doctor-api-keys__muted">${escapeHTML(formattedIp)}</div>`;
			}

			let actionsColumn = `<span class="mail-doctor-api-keys__muted">${escapeHTML(i18n.apiKeyRevoked || 'Revoked')}</span>`;
			if (canRevoke) {
				actionsColumn = `<button type="button" class="button button-link-delete mail-doctor-api-keys__revoke" data-mail-doctor-api-key-revoke="${id}">${escapeHTML(i18n.apiKeyRevoke || 'Revoke')}</button>`;
			}

			return `
				<tr data-mail-doctor-api-key="${id}" data-status="${status}">
					<td class="mail-doctor-api-keys__cell mail-doctor-api-keys__cell--label">
						<strong class="mail-doctor-api-keys__name">${label}</strong>
						<span class="mail-doctor-api-keys__id">${displayId}</span>
						<span class="mail-doctor-api-keys__status mail-doctor-api-keys__status--${status}">${statusLabel}</span>
					</td>
					<td class="mail-doctor-api-keys__cell mail-doctor-api-keys__cell--scopes">${scopesHtml}</td>
					<td class="mail-doctor-api-keys__cell mail-doctor-api-keys__cell--timestamp">${createdColumn}</td>
					<td class="mail-doctor-api-keys__cell mail-doctor-api-keys__cell--usage">${lastColumn}</td>
					<td class="mail-doctor-api-keys__cell mail-doctor-api-keys__cell--actions">${actionsColumn}</td>
				</tr>
			`;
		}

		function render() {
			if (!listBody) {
				return;
			}

			if (!state.keys.length) {
				listBody.innerHTML = '';
				if (emptyState) {
					emptyState.hidden = false;
				}
				return;
			}

			const rows = state.keys.map((item) => renderRow(item)).join('');
			listBody.innerHTML = rows;
			if (emptyState) {
				emptyState.hidden = true;
			}
		}

		function setSubmitting(isSubmitting) {
			if (!submitButton) {
				return;
			}

			submitButton.disabled = Boolean(isSubmitting);
			if (isSubmitting) {
				submitButton.textContent = i18n.apiKeyCreating || 'Generating…';
			} else {
				submitButton.textContent = defaultButtonText;
			}
		}

		function ensureDefaultScopeSelected() {
			if (!scopeInputs.length) {
				return;
			}

			const anyChecked = scopeInputs.some((input) => input.checked);
			if (anyChecked) {
				return;
			}

			const defaultScope = scopeInputs.find((input) => input.hasAttribute('data-mail-doctor-api-scope-default'));
			if (defaultScope) {
				defaultScope.checked = true;
			}
		}

		function syncScopeStates() {
			const fullScope = scopeInputs.find((input) => input.hasAttribute('data-mail-doctor-api-scope-all'));
			if (!fullScope) {
				ensureDefaultScopeSelected();
				return;
			}

			if (fullScope.checked) {
				scopeInputs.forEach((input) => {
					if (input === fullScope) {
						return;
					}
					input.checked = false;
					input.disabled = true;
				});
			} else {
				scopeInputs.forEach((input) => {
					if (input !== fullScope) {
						input.disabled = false;
					}
				});
				ensureDefaultScopeSelected();
			}
		}

		function handleScopeChange(event) {
			if (!event || !event.target) {
				return;
			}

			const input = event.target;

			if (input.hasAttribute('data-mail-doctor-api-scope-all')) {
				syncScopeStates();
				return;
			}

			const fullScope = scopeInputs.find((option) => option.hasAttribute('data-mail-doctor-api-scope-all'));
			if (fullScope && fullScope.checked) {
				fullScope.checked = false;
				fullScope.disabled = false;
			}

			if (!input.checked) {
				ensureDefaultScopeSelected();
			}
		}

		function sendRequest(formData) {
			const options = {
				method: 'POST',
				credentials: 'same-origin',
				body: isURLSearchParams(formData) ? formData.toString() : formData,
			};

			if (isURLSearchParams(formData)) {
				options.headers = {
					'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
				};
			}

			return window
				.fetch(ajaxUrl, options)
				.then((response) =>
					response
						.json()
						.catch(() => null)
						.then((payload) => {
							const success = payload && payload.success;
							if (response.ok && success) {
								return payload.data || {};
							}

							const message = (payload && payload.data && payload.data.message) || i18n.apiKeyErrorGeneric || 'Request failed.';
							throw new Error(message);
						})
				);
		}

		function showSecret(secret, key) {
			if (!secretBox || !secretField) {
				return;
			}

			secretField.value = secret || '';
			secretBox.hidden = false;
			secretField.removeAttribute('readonly');
			secretField.setAttribute('readonly', 'readonly');

			if (secretLabel) {
				const labelText = key && key.label ? String(key.label) : '';
				if (labelText) {
					const template = i18n.apiKeySecretFor || 'Secret generated for %s';
					secretLabel.textContent = template.replace('%s', labelText);
					secretLabel.hidden = false;
				} else {
					secretLabel.textContent = '';
					secretLabel.hidden = true;
				}
			}

			window.setTimeout(() => {
				secretField.focus();
				secretField.select();
			}, 50);
		}

		function handleCreate(event) {
			if (event && typeof event.preventDefault === 'function') {
				event.preventDefault();
			}

			if (!createForm) {
				return;
			}

			clearNotice();
			setSubmitting(true);

			const labelInput = createForm.querySelector('input[name="label"]');
			const labelValue = labelInput ? labelInput.value : '';
			let scopes = scopeInputs.filter((input) => input.checked).map((input) => input.value);
			if (!scopes.length) {
				scopes = ['status.read'];
			}

			const formData = createPayload();
			appendPayload(formData, 'action', 'mail_doctor_create_api_key');
			appendPayload(formData, '_wpnonce', nonces.create || '');
			appendPayload(formData, 'label', labelValue);
			scopes.forEach((scope) => {
				appendPayload(formData, 'scopes[]', scope);
			});

			sendRequest(formData)
				.then((data) => {
					if (!data || !data.key) {
						throw new Error(i18n.apiKeyErrorGeneric || 'Request failed.');
					}

					state.keys.unshift(data.key);
					render();
					updateDataset();
					showSecret(data.secret || '', data.key);
					showNotice('success', i18n.apiKeyCreated || 'API key generated. Copy the secret now.');

					if (createForm && typeof createForm.reset === 'function') {
						createForm.reset();
					} else {
						resetCreateControls();
					}

					syncScopeStates();
				})
				.catch((error) => {
					showNotice('error', (error && error.message) || i18n.apiKeyErrorGeneric || 'Request failed.');
				})
				.finally(() => {
					setSubmitting(false);
				});
		}

		function handleRevoke(trigger) {
			if (!trigger) {
				return;
			}

			const id = trigger.getAttribute('data-mail-doctor-api-key-revoke');
			if (!id) {
				return;
			}

			const confirmMessage = i18n.apiKeyRevokeConfirm || 'Revoke this API key?';
			if (!window.confirm(confirmMessage)) {
				return;
			}

			const originalText = trigger.textContent;
			trigger.disabled = true;
			trigger.textContent = i18n.loading || 'Loading…';

			const formData = createPayload();
			appendPayload(formData, 'action', 'mail_doctor_revoke_api_key');
			appendPayload(formData, '_wpnonce', nonces.revoke || '');
			appendPayload(formData, 'id', id);

			sendRequest(formData)
				.then(() => {
					state.keys = state.keys.filter((key) => key && key.id !== id);
					render();
					updateDataset();
					showNotice('success', i18n.apiKeyRevoked || 'API key revoked.');
				})
				.catch((error) => {
					showNotice('error', (error && error.message) || i18n.apiKeyErrorGeneric || 'Request failed.');
				})
				.finally(() => {
					trigger.disabled = false;
					trigger.textContent = originalText;
				});
		}

		if (createForm) {
			if (isFormElement) {
				createForm.addEventListener('submit', handleCreate);
			} else {
				if (submitButton) {
					submitButton.addEventListener('click', (event) => {
						if (event && typeof event.preventDefault === 'function') {
							event.preventDefault();
						}
						handleCreate(event);
					});
				}

				createForm.addEventListener('keydown', (event) => {
					if (!event || event.defaultPrevented || 'Enter' !== event.key) {
						return;
					}

					const trigger = createForm.querySelector(API_CREATE_TRIGGER_SELECTOR);
					if (!trigger) {
						return;
					}

					event.preventDefault();
					trigger.click();
				});
			}
		}

		scopeInputs.forEach((input) => {
			input.addEventListener('change', handleScopeChange);
		});

		syncScopeStates();
		render();
		container._mdApiKeys = {
			handleRevoke,
			handleCreate,
		};
	}

	app.register((appInstance) => {
		document.addEventListener(
			'click',
			(event) => {
				if (!event || event.defaultPrevented) {
					return;
				}

				const createTrigger = event.target.closest(API_CREATE_TRIGGER_SELECTOR);

				if (createTrigger) {
					event.preventDefault();
					const apiContainer = createTrigger.closest('[data-mail-doctor-api-keys]');

					if (apiContainer && apiContainer._mdApiKeys && typeof apiContainer._mdApiKeys.handleCreate === 'function') {
						apiContainer._mdApiKeys.handleCreate(event);
					}

					return;
				}

				const copyTrigger = event.target.closest('.mail-doctor-copy-trigger');

				if (copyTrigger) {
					event.preventDefault();
					const selector = copyTrigger.getAttribute('data-mail-doctor-copy-source');
					copyFromSelector(selector, copyTrigger);
					return;
				}

				const regenerateTrigger = event.target.closest('.mail-doctor-regenerate-secret');

				if (regenerateTrigger) {
					event.preventDefault();
					handleRegenerate(regenerateTrigger);
					return;
				}

				const revokeTrigger = event.target.closest('[data-mail-doctor-api-key-revoke]');

				if (revokeTrigger) {
					event.preventDefault();
					const apiContainer = revokeTrigger.closest('[data-mail-doctor-api-keys]');

					if (apiContainer && apiContainer._mdApiKeys && typeof apiContainer._mdApiKeys.handleRevoke === 'function') {
						apiContainer._mdApiKeys.handleRevoke(revokeTrigger);
					}

					return;
				}
			},
			false
		);

		initApiKeys(appInstance);
	});
})(window, document);
