(function () {
	'use strict';

	if (typeof wppsAdminColorCustomizer === 'undefined') {
		return;
	}

	var cfg = wppsAdminColorCustomizer;
	var state = JSON.parse(JSON.stringify(cfg.settings || {}));
	var schemes = cfg.schemes || {};
	var originalSchemes = JSON.parse(JSON.stringify(schemes));
	var builtInIds = cfg.builtInSchemes || [];
	var pendingActiveScheme = null;
	var customCssEditor = null;
	var premiumModes = ['force_all', 'force_by_role'];
	var colorKeys = [
		'primary', 'secondary', 'accent',
		'menu_bg', 'menu_text', 'menu_hover_bg', 'menu_hover_text',
		'toolbar_bg', 'toolbar_text',
		'button_bg', 'button_text', 'notice'
	];

	// PHP serialises an empty associative array as a JSON array ([]). Assigning a
	// string key to a JS array is silently dropped by JSON.stringify, which would
	// throw away saved custom schemes. Force a plain object so saves persist.
	function ensureCustomSchemesObject() {
		if (!state.custom_schemes || typeof state.custom_schemes !== 'object' || Array.isArray(state.custom_schemes)) {
			state.custom_schemes = {};
		}
		return state.custom_schemes;
	}
	ensureCustomSchemesObject();

	function isPremiumUnlocked() {
		return cfg.premiumUnlocked === true || cfg.premiumUnlocked === 1 || cfg.premiumUnlocked === '1';
	}

	function schemeDisplayName(schemeId) {
		if (schemes[schemeId] && schemes[schemeId].name) {
			return schemes[schemeId].name;
		}
		return schemeId;
	}

	function $(selector, root) {
		return (root || document).querySelector(selector);
	}

	function $all(selector, root) {
		return Array.prototype.slice.call((root || document).querySelectorAll(selector));
	}

	function notice(message, type) {
		var box = $('#wpps-acc-notices');
		if (!box) {
			return;
		}
		box.innerHTML = '<div class="notice notice-' + (type || 'success') + ' is-dismissible"><p>' + message + '</p></div>';
	}

	function hexValid(value) {
		return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(String(value || '').trim());
	}

	function expandHex(color) {
		if (!hexValid(color)) {
			return null;
		}
		if (color.length === 4) {
			return '#' + color[1] + color[1] + color[2] + color[2] + color[3] + color[3];
		}
		return color.toLowerCase();
	}

	function getActiveSchemeId() {
		var selected = $('input[name="wpps_acc_active_scheme"]:checked');
		if (selected) {
			return selected.value;
		}
		var select = $('#wpps-acc-active-scheme-select');
		if (select && select.value) {
			return select.value;
		}
		return state.active_scheme || 'powersuite_blue';
	}

	function setBuilderColorField(key, color) {
		if (!color) {
			return;
		}

		var input = $('[data-builder-field="' + key + '"]');
		if (input) {
			input.value = color;
			input.setAttribute('data-default-color', color);
			var pickerId = input.getAttribute('data-color-input');
			if (pickerId) {
				var picker = document.getElementById(pickerId);
				if (picker) {
					picker.value = color.length > 7 ? color.substring(0, 7) : color;
				}
			}
			var wrap = input.closest('.wpps-color-code-wrap');
			if (wrap) {
				var resetBtn = wrap.querySelector('.wpps-color-reset');
				if (resetBtn) {
					resetBtn.setAttribute('data-default-color', color);
				}
			}
		}
	}

	function applyColorsToBuilder(colors, options) {
		options = options || {};

		if (!colors) {
			return;
		}

		colorKeys.forEach(function (key) {
			if (colors[key]) {
				setBuilderColorField(key, colors[key]);
			}
		});

		if (options.updateScheme !== false) {
			var id = getActiveSchemeId();
			if (schemes[id]) {
				colorKeys.forEach(function (key) {
					if (colors[key]) {
						schemes[id][key] = colors[key];
					}
				});
			}

			if (state.custom_schemes && state.custom_schemes[id]) {
				colorKeys.forEach(function (key) {
					if (colors[key]) {
						state.custom_schemes[id][key] = colors[key];
					}
				});
			}
		}

		if (options.refresh !== false) {
			refreshPreviewAndContrast();
		}
	}

	function applyPresetToBuilder(schemeId) {
		var preset = schemes[schemeId];
		if (!preset) {
			return;
		}

		applyColorsToBuilder(preset);
	}

	function getBuilderScheme() {
		var schemeId = ($('[data-builder-field="id"]') || {}).value || getActiveSchemeId();
		var scheme = {
			id: schemeId,
			name: schemeDisplayName(schemeId)
		};

		colorKeys.forEach(function (key) {
			var input = $('[data-builder-field="' + key + '"]');
			scheme[key] = input ? input.value : (schemes[scheme.id] && schemes[scheme.id][key]) || '#000000';
		});

		return scheme;
	}

	function getPreviewScheme() {
		var id = getActiveSchemeId();
		var base = schemes[id] ? JSON.parse(JSON.stringify(schemes[id])) : getBuilderScheme();
		var builder = getBuilderScheme();

		if (cfg.currentView === 'colors' || cfg.currentView === 'setup') {
			colorKeys.forEach(function (key) {
				if (hexValid(builder[key])) {
					base[key] = builder[key];
				}
			});
		}

		return base;
	}

	function applyPreview(scheme) {
		var preview = $('#wpps-acc-preview');
		if (!preview || !scheme) {
			return;
		}

		var toolbar = $('[data-part="toolbar"]', preview);
		var menu = $('[data-part="menu"]', preview);
		var submenu = $('[data-part="submenu"]', preview);
		var primary = $('[data-part="button-primary"]', preview);
		var secondary = $('[data-part="button-secondary"]', preview);
		var noticeEl = $('[data-part="notice"]', preview);

		if (toolbar) {
			toolbar.style.backgroundColor = scheme.toolbar_bg;
			toolbar.style.color = scheme.toolbar_text;
		}
		if (menu) {
			menu.style.backgroundColor = scheme.menu_bg;
			menu.style.color = scheme.menu_text;
		}
		if (submenu) {
			submenu.style.backgroundColor = scheme.menu_bg;
		}
		$all('.wpps-acc-preview__menu-item.is-current', preview).forEach(function (el) {
			el.style.backgroundColor = scheme.primary;
			el.style.color = scheme.menu_hover_text;
		});
		$all('.wpps-acc-preview__menu-item.is-hover, .wpps-acc-preview__submenu-item.is-hover', preview).forEach(function (el) {
			el.style.backgroundColor = scheme.menu_hover_bg;
			el.style.color = scheme.menu_hover_text;
		});
		if (primary) {
			primary.style.backgroundColor = scheme.button_bg;
			primary.style.color = scheme.button_text;
			primary.style.borderColor = scheme.secondary;
		}
		if (secondary) {
			secondary.style.color = scheme.primary;
			secondary.style.borderColor = scheme.primary;
			secondary.style.backgroundColor = '#fff';
		}
		if (noticeEl) {
			noticeEl.style.borderLeftColor = scheme.notice;
		}
	}

	function renderA11yWarnings(warnings) {
		var box = $('#wpps-acc-a11y-warnings');
		if (!box) {
			return;
		}
		if (!warnings || !warnings.length) {
			box.innerHTML = '<div class="notice notice-success inline"><p>' + cfg.strings.contrastPass + '</p></div>';
			return;
		}
		box.innerHTML = warnings.map(function (warning) {
			return '<div class="notice notice-warning inline"><p><strong>' + cfg.strings.contrastWarning + ':</strong> ' +
				warning.label + ' (' + warning.ratio + ':1, min ' + warning.minimum + ')</p></div>';
		}).join('');
	}

	function ajax(action, data) {
		var body = new FormData();
		body.append('action', action);
		body.append('nonce', cfg.nonce);
		Object.keys(data || {}).forEach(function (key) {
			body.append(key, typeof data[key] === 'object' ? JSON.stringify(data[key]) : data[key]);
		});

		return fetch(cfg.ajaxUrl, {
			method: 'POST',
			credentials: 'same-origin',
			body: body
		}).then(function (response) {
			return response.json();
		});
	}

	// Persist colors edited in the "Customize active scheme" builder when the user
	// clicks the main Save button. Built-in schemes get a same-id custom override
	// (which wins in get_all_schemes); custom schemes are updated in place.
	function syncActiveSchemeOverride() {
		if (!isPremiumUnlocked()) {
			return;
		}

		if (!$('[data-builder-field="primary"]')) {
			return;
		}

		var activeId = state.active_scheme || getActiveSchemeId();
		if (!activeId) {
			return;
		}

		var builder = getBuilderScheme();
		builder.id = activeId;
		builder.built_in = false;

		var allValid = colorKeys.every(function (key) {
			return hexValid(builder[key]);
		});
		if (!allValid) {
			return;
		}

		var orig = originalSchemes[activeId];
		var changed = !orig || colorKeys.some(function (key) {
			return expandHex(builder[key]) !== expandHex(orig[key]);
		});
		var schemesObj = ensureCustomSchemesObject();
		var alreadyOverridden = Object.prototype.hasOwnProperty.call(schemesObj, activeId);
		var isBuiltIn = builtInIds.indexOf(activeId) !== -1;

		if (isBuiltIn && !changed && !alreadyOverridden) {
			return;
		}

		if (!builder.name) {
			builder.name = schemeDisplayName(activeId);
		}

		schemesObj[activeId] = builder;
		schemes[activeId] = builder;
		return true;
	}

	function collectSettingsFromDom() {
		$all('[data-setting]').forEach(function (el) {
			var path = el.getAttribute('data-setting');
			var parts = path.split('.');
			var value;

			if (el.type === 'checkbox') {
				value = el.checked;
			} else {
				value = el.value;
			}

			if (parts.length === 1) {
				state[parts[0]] = value;
			} else if (parts.length === 2) {
				state[parts[0]] = state[parts[0]] || {};
				state[parts[0]][parts[1]] = value;
			}
		});

		var roleSchemes = {};
		$all('[data-role-scheme]').forEach(function (select) {
			if (select.value) {
				roleSchemes[select.getAttribute('data-role-scheme')] = select.value;
			}
		});
		state.role_schemes = roleSchemes;

		var active = pendingActiveScheme || getActiveSchemeId();
		if (active) {
			state.active_scheme = active;
		}

		return state;
	}

	function refreshPreviewAndContrast() {
		var scheme = getPreviewScheme();
		applyPreview(scheme);
		ajax('wpps_acc_check_contrast', { scheme: scheme }).then(function (response) {
			if (response && response.success) {
				renderA11yWarnings(response.data.warnings || []);
			}
		});
	}

	function bindColorInputs() {
		$all('[data-builder-field], .wpps-color-code-input[data-setting]').forEach(function (el) {
			el.addEventListener('input', refreshPreviewAndContrast);
			el.addEventListener('change', refreshPreviewAndContrast);
		});

		document.addEventListener('click', function (event) {
			var resetBtn = event.target && event.target.closest ? event.target.closest('.wpps-acc-wrap .wpps-color-reset') : null;
			if (!resetBtn) {
				return;
			}

			var defaultColor = resetBtn.getAttribute('data-default-color') || '';
			var wrap = resetBtn.closest('.wpps-color-code-wrap');
			if (!wrap) {
				return;
			}

			var textInput = wrap.querySelector('.wpps-color-code-input');
			if (!textInput) {
				return;
			}

			textInput.value = defaultColor;
			var pickerId = textInput.getAttribute('data-color-input');
			if (pickerId) {
				var picker = document.getElementById(pickerId);
				if (picker) {
					picker.value = defaultColor.length > 7 ? defaultColor.substring(0, 7) : defaultColor;
				}
			}

			textInput.dispatchEvent(new Event('change', { bubbles: true }));
		});

		function onActiveSchemeChange(schemeId) {
			var select = $('#wpps-acc-active-scheme-select');
			if (select) {
				select.value = schemeId;
			}
			$all('input[name="wpps_acc_active_scheme"]').forEach(function (radio) {
				radio.checked = radio.value === schemeId;
			});
			state.active_scheme = schemeId;
			applyPresetToBuilder(schemeId);
			refreshPreviewAndContrast();
		}

		$all('input[name="wpps_acc_active_scheme"]').forEach(function (radio) {
			radio.addEventListener('change', function () {
				onActiveSchemeChange(radio.value);
			});
		});

		var schemeSelect = $('#wpps-acc-active-scheme-select');
		if (schemeSelect) {
			schemeSelect.addEventListener('change', function () {
				onActiveSchemeChange(schemeSelect.value);
			});
		}

		var modeSelect = $('#wpps-acc-mode');
		if (modeSelect) {
			modeSelect.addEventListener('change', function () {
				if (!isPremiumUnlocked() && premiumModes.indexOf(modeSelect.value) !== -1) {
					modeSelect.value = 'global_default';
				}
				var help = $('#wpps-acc-mode-help');
				var labels = {
					disabled: 'No custom admin colors are output.',
					global_default: 'Apply the active scheme site-wide. Users can pick a PowerSuite scheme in their profile.',
					force_all: 'Always use the active scheme for every user.',
					force_by_role: 'Map roles to schemes on the Advanced tab.',
					per_user_selectable: 'Custom schemes appear in the profile color picker.'
				};
				if (help) {
					help.textContent = labels[modeSelect.value] || '';
				}
				collectSettingsFromDom();
			});
		}

		$all('[data-setting], [data-role-scheme]').forEach(function (el) {
			el.addEventListener('change', collectSettingsFromDom);
		});
	}

	function saveSettings(saveScope, reloadOnColorChange) {
		collectSettingsFromDom();
		var colorsChanged = syncActiveSchemeOverride() === true;
		var saveBtn = $('#wpps-acc-save');
		if (saveBtn) {
			saveBtn.disabled = true;
			saveBtn.textContent = cfg.strings.saving;
		}

		return ajax('wpps_acc_save_settings', {
			settings: JSON.stringify(state),
			save_scope: saveScope || 'site'
		}).then(function (response) {
			if (saveBtn) {
				saveBtn.disabled = false;
				saveBtn.textContent = 'Save settings';
			}
			if (!response || !response.success) {
				notice((response && response.data && response.data.message) || cfg.strings.errorGeneric, 'error');
				return;
			}
			state = response.data.settings || state;
			ensureCustomSchemesObject();
			Object.keys(state.custom_schemes).forEach(function (id) {
				schemes[id] = state.custom_schemes[id];
				originalSchemes[id] = JSON.parse(JSON.stringify(state.custom_schemes[id]));
			});
			renderA11yWarnings(response.data.accessibility || []);
			notice(cfg.strings.saved, 'success');

			// Reload so the admin chrome (menu/bar) and preset palette reflect the
			// freshly-saved scheme colors, which are rendered server-side.
			if (reloadOnColorChange && colorsChanged) {
				window.setTimeout(function () {
					window.location.reload();
				}, 350);
			}
		}).catch(function () {
			if (saveBtn) {
				saveBtn.disabled = false;
			}
			notice(cfg.strings.errorGeneric, 'error');
		});
	}

	function initActions() {
		var saveBtn = $('#wpps-acc-save');
		if (saveBtn) {
			saveBtn.addEventListener('click', function () {
				var scope = cfg.canManageNetwork ? 'site' : 'site';
				saveSettings(scope, true);
			});
		}

		var resetAccessible = $('#wpps-acc-reset-accessible');
		if (resetAccessible) {
			resetAccessible.addEventListener('click', function () {
				applyColorsToBuilder(cfg.accessibleDefaults || {});
				notice(cfg.strings.resetAccessibleApplied, 'info');
			});
		}

		var resetAll = $('#wpps-acc-reset-all');
		if (resetAll) {
			resetAll.addEventListener('click', function () {
				if (!window.confirm(cfg.strings.confirmResetAll)) {
					return;
				}
				ajax('wpps_acc_reset_scheme', { reset_type: 'all' }).then(function () {
					window.location.reload();
				});
			});
		}

		var allowCss = $('#wpps-acc-allow-custom-css');
		var customCss = $('#wpps-acc-custom-css');
		if (allowCss && customCss) {
			allowCss.addEventListener('change', function () {
				customCss.disabled = !allowCss.checked;
				if (customCssEditor && customCssEditor.codemirror) {
					customCssEditor.codemirror.setOption('readOnly', !allowCss.checked);
				}
				if (allowCss.checked) {
					notice(cfg.strings.customCssWarning, 'warning');
				}
			});
		}
	}

	function initCustomCssEditor() {
		var panel = $('.wpps-acc-custom-css-panel');
		var textarea = $('#wpps-acc-custom-css');
		if (!panel || !textarea || !window.wp || !window.wp.codeEditor) {
			return;
		}
		if (textarea.nextElementSibling && textarea.nextElementSibling.classList.contains('CodeMirror')) {
			return;
		}

		var height = parseInt(panel.getAttribute('data-editor-height'), 10) || 220;
		panel.style.setProperty('--cs-editor-height', height + 'px');

		try {
			customCssEditor = window.wp.codeEditor.initialize(textarea, {
				codemirror: {
					mode: 'css',
					lineNumbers: true,
					lineWrapping: true,
					styleActiveLine: true,
					matchBrackets: true,
					autoCloseBrackets: true,
					readOnly: textarea.disabled,
					height: height + 'px'
				}
			});
			if (customCssEditor && customCssEditor.codemirror) {
				customCssEditor.codemirror.on('change', function () {
					customCssEditor.codemirror.save();
					collectSettingsFromDom();
				});
			}
		} catch (e) {
			if (window.console && typeof window.console.warn === 'function') {
				window.console.warn('WP PowerSuite: Admin Color Customizer CSS editor failed to initialize.', e);
			}
		}
	}

	bindColorInputs();
	initActions();
	initCustomCssEditor();
	refreshPreviewAndContrast();
})();
