'use strict';

function initSubmissionInboxPublishing(editor) {
	var state = editor && editor.__subinSaveState;
	var shell = document.querySelector('[data-subin-studio-shell]');
	var layer = shell ? shell.querySelector('[data-subin-studio-publish-layer]') : null;

	if (!state || !shell || !layer || state.publishingReady) {
		return;
	}

	state.publishingReady = true;
	state.publishButton = shell.querySelector('[data-subin-studio-publish]');
	state.publishConfirm = layer.querySelector('[data-subin-studio-publish-confirm]');
	state.publishStatus = layer.querySelector('[data-subin-studio-publish-status]');
	state.publishSummary = layer.querySelector('[data-subin-studio-publish-summary]');
	state.historyHost = layer.querySelector('[data-subin-studio-history]');
	state.preflightButton = layer.querySelector('[data-subin-studio-preflight-run]');
	state.preflightBadge = layer.querySelector('[data-subin-studio-preflight-badge]');
	state.preflightResults = layer.querySelector('[data-subin-studio-preflight-results]');
	state.sandboxButton = layer.querySelector('[data-subin-studio-sandbox-run]');
	state.sandboxResult = layer.querySelector('[data-subin-studio-sandbox-result]');
	state.history = Array.isArray(state.formData.history) ? state.formData.history.slice() : [];
	state.publishedAt = String(state.formData.published_at || '');
	state.publishing = false;
	state.preflight = null;
	state.preflightError = '';
	state.preflightRunning = false;
	state.sandboxRunning = false;

	if (state.publishButton) {
		state.publishButton.addEventListener('click', function () {
			layer.hidden = false;
			shell.classList.add('is-publish-open');
			renderSubmissionInboxPublishingHistory(state);
			renderSubmissionInboxPreflight(state);
			updateSubmissionInboxPublishingState(state);
			runSubmissionInboxPreflight(state, false);
			if (state.preflightButton) {
				state.preflightButton.focus();
			}
		});
	}
	layer.querySelectorAll('[data-subin-studio-publish-close]').forEach(function (button) {
		button.addEventListener('click', function () {
			closeSubmissionInboxPublishing(shell, layer, state);
		});
	});
	if (state.publishConfirm) {
		state.publishConfirm.addEventListener('click', function () {
			publishSubmissionInboxDraft(state);
		});
	}
	if (state.preflightButton) {
		state.preflightButton.addEventListener('click', function () {
			runSubmissionInboxPreflight(state, true);
		});
	}
	if (state.sandboxButton) {
		state.sandboxButton.addEventListener('click', function () {
			runSubmissionInboxSandbox(state);
		});
	}
	if (state.historyHost) {
		state.historyHost.addEventListener('click', function (event) {
			var button = event.target && event.target.closest
				? event.target.closest('[data-subin-restore-revision]')
				: null;
			if (button) {
				restoreSubmissionInboxDraftRevision(state, button.getAttribute('data-subin-restore-revision'));
			}
		});
	}
	document.addEventListener('keydown', function (event) {
		if (event.key === 'Escape' && !layer.hidden) {
			closeSubmissionInboxPublishing(shell, layer, state);
		}
	});

	renderSubmissionInboxPublishingHistory(state);
	renderSubmissionInboxPreflight(state);
	updateSubmissionInboxPublishingState(state);
}

function closeSubmissionInboxPublishing(shell, layer, state) {
	layer.hidden = true;
	shell.classList.remove('is-publish-open');
	if (state.publishButton) {
		state.publishButton.focus();
	}
}

function updateSubmissionInboxPublishingState(state) {
	var preflightReady = hasCurrentSubmissionInboxPreflight(state);
	var canPublish = !!state.publishedDirty &&
		state.phase !== 'conflict' &&
		!state.publishing &&
		!state.preflightRunning &&
		preflightReady;

	if (!state || !state.publishingReady) {
		return;
	}
	if (state.publishButton) {
		state.publishButton.classList.toggle('has-unpublished-changes', !!state.publishedDirty);
		state.publishButton.setAttribute(
			'aria-label',
			state.publishedDirty ? 'Publish saved draft changes' : 'Open Publish and Embed'
		);
	}
	if (state.publishConfirm) {
		state.publishConfirm.disabled = !canPublish;
		state.publishConfirm.textContent = state.publishing ? 'Publishing...' : 'Publish changes';
	}
	if (state.preflightButton) {
		state.preflightButton.disabled = !!state.preflightRunning || !!state.publishing;
		state.preflightButton.textContent = state.preflightRunning ? 'Checking...' : 'Run checks';
	}
	if (state.sandboxButton) {
		state.sandboxButton.disabled = !preflightReady || !!state.sandboxRunning || !!state.publishing;
		state.sandboxButton.textContent = state.sandboxRunning ? 'Simulating...' : 'Run safe simulation';
	}
	if (state.publishSummary) {
		var title = state.publishSummary.querySelector('strong');
		var detail = state.publishSummary.querySelector('p');
		state.publishSummary.classList.toggle('is-ready', !!state.publishedDirty);
		if (title) {
			title.textContent = state.publishedDirty ? 'Draft ready to publish' : 'Published version is up to date';
		}
		if (detail) {
			detail.textContent = state.publishedDirty
				? 'Your saved draft is private until you publish it.'
				: 'There are no unpublished draft changes.';
		}
	}
}

function publishSubmissionInboxDraft(state) {
	if (!state || state.publishing || state.phase === 'conflict' || !state.publishedDirty) {
		return;
	}

	saveSubmissionInboxDraftBeforePublish(state)
		.then(function (ready) {
			if (!ready || state.publishing) {
				return false;
			}
			if (hasCurrentSubmissionInboxPreflight(state)) {
				return true;
			}
			return runSubmissionInboxPreflight(state, true);
		})
		.then(function (ready) {
			var ajax;
			var body;

			if (!ready || state.publishing) {
				return;
			}

			ajax = state.formData.ajax || {};
			body = new window.URLSearchParams();
			body.set('action', ajax.publish_action || 'subin_publish_grapesjs_draft');
			body.set('form_id', String(state.formData.id || ''));
			body.set('nonce', ajax.publish_nonce || '');
			body.set('revision', String(state.revision || 0));
			body.set('published_revision', String(state.publishedRevision || 0));
			state.publishing = true;
			setSubmissionInboxPublishStatus(state, 'Publishing...', '');
			updateSubmissionInboxPublishingState(state);

			return submissionInboxPublishingRequest(ajax.url || window.ajaxurl, body)
				.then(function (data) {
					if (submissionInboxOwn(data, 'revision')) {
						setSubmissionInboxRevision(state, data.revision);
					}
					if (submissionInboxOwn(data, 'published_revision')) {
						state.publishedRevision = Math.max(0, parseInt(data.published_revision || 0, 10) || 0);
						state.formData.published_revision = state.publishedRevision;
					}
					if (data.project && typeof data.project === 'object') {
						applySubmissionInboxCanonicalProject(state.editor, data.project, state.formData, state);
					}
					state.publishedDirty = false;
					state.formData.is_dirty = false;
					state.publishedAt = String(data.published_at || '');
					state.formData.published_at = state.publishedAt;
					state.history = Array.isArray(data.history) ? data.history.slice() : state.history;
					state.formData.history = state.history.slice();
					state.savedVersion = state.changeVersion;
					if (state.editor.clearDirtyCount) {
						state.editor.clearDirtyCount();
					}
					setGrapesJSSaveState(state, 'saved', 'Published just now');
					setSubmissionInboxPublishStatus(state, data.message || 'Form published.', 'success');
					invalidateSubmissionInboxPreflight(state);
					renderSubmissionInboxPublishingHistory(state);
				})
				.catch(function (error) {
					if (error.data && submissionInboxOwn(error.data, 'revision')) {
						setSubmissionInboxRevision(state, error.data.revision);
					}
					if (error.data && submissionInboxOwn(error.data, 'published_revision')) {
						state.publishedRevision = Math.max(0, parseInt(error.data.published_revision || 0, 10) || 0);
					}
					if (error.data && error.data.preflight) {
						state.preflight = error.data.preflight;
						state.preflightError = error.message || '';
						renderSubmissionInboxPreflight(state);
					}
					setSubmissionInboxPublishStatus(state, error.message || 'Form could not be published.', 'error');
				})
				.finally(function () {
					state.publishing = false;
					updateSubmissionInboxPublishingState(state);
				});
		});
}

function saveSubmissionInboxDraftBeforePublish(state) {
	return waitForSubmissionInboxDraftIdle(state, 0).then(function (idle) {
		if (!idle) {
			return false;
		}
		if (state.changeVersion === state.savedVersion && state.phase === 'saved') {
			return true;
		}

		window.clearTimeout(state.autoSaveTimer);
		state.autoSaveTimer = 0;
		return saveGrapesJSProject(state.editor, state.formData, state.button, state).then(function () {
			return state.phase === 'saved' && state.changeVersion === state.savedVersion;
		});
	});
}

function waitForSubmissionInboxDraftIdle(state, attempt) {
	if (!state || state.phase !== 'saving') {
		return window.Promise.resolve(true);
	}
	if (attempt >= 100) {
		return window.Promise.resolve(false);
	}
	return new window.Promise(function (resolve) {
		window.setTimeout(function () {
			resolve(waitForSubmissionInboxDraftIdle(state, attempt + 1));
		}, 50);
	});
}

function runSubmissionInboxPreflight(state, announce) {
	var ajax;
	var body;

	if (!state || state.preflightRunning || state.publishing) {
		return window.Promise.resolve(false);
	}

	return saveSubmissionInboxDraftBeforePublish(state)
		.then(function (ready) {
			if (!ready) {
				state.preflightError = 'Save the draft before running checks.';
				renderSubmissionInboxPreflight(state);
				if (announce) {
					setSubmissionInboxPublishStatus(state, state.preflightError, 'error');
				}
				return false;
			}

			ajax = state.formData.ajax || {};
			body = new window.URLSearchParams();
			body.set('action', ajax.preflight_action || 'subin_form_preflight');
			body.set('form_id', String(state.formData.id || ''));
			body.set('nonce', ajax.preflight_nonce || '');
			body.set('revision', String(state.revision || 0));
			body.set('published_revision', String(state.publishedRevision || 0));
			state.preflightRunning = true;
			state.preflightError = '';
			renderSubmissionInboxPreflight(state);
			updateSubmissionInboxPublishingState(state);

			return submissionInboxPublishingRequest(ajax.url || window.ajaxurl, body);
		})
		.then(function (data) {
			if (data === false) {
				return false;
			}
			state.preflight = data;
			state.preflightError = '';
			renderSubmissionInboxPreflight(state);
			if (announce) {
				setSubmissionInboxPublishStatus(
					state,
					data.ready ? 'Pre-publish checks completed.' : 'Resolve the failed checks before publishing.',
					data.ready ? 'success' : 'error'
				);
			}
			return hasCurrentSubmissionInboxPreflight(state);
		})
		.catch(function (error) {
			if (error.data && submissionInboxOwn(error.data, 'revision')) {
				setSubmissionInboxRevision(state, error.data.revision);
			}
			if (error.data && submissionInboxOwn(error.data, 'published_revision')) {
				state.publishedRevision = Math.max(0, parseInt(error.data.published_revision || 0, 10) || 0);
			}
			state.preflight = null;
			state.preflightError = error.message || 'Pre-publish checks could not run.';
			renderSubmissionInboxPreflight(state);
			if (announce) {
				setSubmissionInboxPublishStatus(state, state.preflightError, 'error');
			}
			return false;
		})
		.finally(function () {
			state.preflightRunning = false;
			renderSubmissionInboxPreflight(state);
			updateSubmissionInboxPublishingState(state);
		});
}

function hasCurrentSubmissionInboxPreflight(state) {
	return !!(
		state &&
		state.preflight &&
		state.preflight.ready &&
		String(state.preflight.revision || 0) === String(state.revision || 0) &&
		String(state.preflight.published_revision || 0) === String(state.publishedRevision || 0)
	);
}

function invalidateSubmissionInboxPreflight(state) {
	if (!state) {
		return;
	}
	state.preflight = null;
	state.preflightError = '';
	if (state.sandboxResult) {
		state.sandboxResult.hidden = true;
		state.sandboxResult.innerHTML = '';
	}
	renderSubmissionInboxPreflight(state);
}

function renderSubmissionInboxPreflight(state) {
	var badge;
	var checks;
	var counts;
	var ready;
	var warningCount;
	var failCount;

	if (!state || !state.preflightBadge || !state.preflightResults) {
		return;
	}
	badge = state.preflightBadge;
	if (state.preflightRunning) {
		badge.textContent = 'Checking...';
		badge.setAttribute('data-status', 'running');
		state.preflightResults.innerHTML = '<p class="subin-studio-preflight__empty">Checking the saved draft and delivery setup...</p>';
		return;
	}
	if (state.preflightError) {
		badge.textContent = 'Check failed';
		badge.setAttribute('data-status', 'fail');
		state.preflightResults.innerHTML = '<p class="subin-studio-preflight__error">' +
			escapeSubmissionInboxPublishingHtml(state.preflightError) +
			'</p>';
		return;
	}
	if (!state.preflight) {
		badge.textContent = 'Not checked';
		badge.setAttribute('data-status', 'idle');
		state.preflightResults.innerHTML = '<p class="subin-studio-preflight__empty">Run checks for the current saved draft.</p>';
		return;
	}

	checks = Array.isArray(state.preflight.checks) ? state.preflight.checks : [];
	counts = state.preflight.counts || {};
	ready = hasCurrentSubmissionInboxPreflight(state);
	warningCount = Math.max(0, parseInt(counts.warning || 0, 10) || 0);
	failCount = Math.max(0, parseInt(counts.fail || 0, 10) || 0);

	if (ready && warningCount > 0) {
		badge.textContent = 'Ready, ' + warningCount + ' warning' + (warningCount === 1 ? '' : 's');
		badge.setAttribute('data-status', 'warning');
	} else if (ready) {
		badge.textContent = 'Ready';
		badge.setAttribute('data-status', 'pass');
	} else if (failCount > 0) {
		badge.textContent = 'Fix ' + failCount + ' issue' + (failCount === 1 ? '' : 's');
		badge.setAttribute('data-status', 'fail');
	} else {
		badge.textContent = 'Out of date';
		badge.setAttribute('data-status', 'idle');
	}

	state.preflightResults.innerHTML = checks.map(function (check) {
		var status = /^(pass|warning|fail|info)$/.test(String(check.status || ''))
			? String(check.status)
			: 'info';
		var marker = {pass: 'OK', warning: '!', fail: 'FIX', info: 'i'}[status];
		return '<div class="subin-studio-preflight-item" data-status="' + status + '">' +
			'<span class="subin-studio-preflight-item__marker" aria-hidden="true">' + marker + '</span>' +
			'<div><strong>' + escapeSubmissionInboxPublishingHtml(check.label || '') + '</strong>' +
			'<p>' + escapeSubmissionInboxPublishingHtml(check.message || '') + '</p></div></div>';
	}).join('');
}

function runSubmissionInboxSandbox(state) {
	var ajax;
	var body;

	if (!hasCurrentSubmissionInboxPreflight(state) || state.sandboxRunning || state.publishing) {
		return;
	}
	ajax = state.formData.ajax || {};
	body = new window.URLSearchParams();
	body.set('action', ajax.sandbox_action || 'subin_form_sandbox');
	body.set('form_id', String(state.formData.id || ''));
	body.set('nonce', ajax.sandbox_nonce || '');
	body.set('revision', String(state.revision || 0));
	body.set('published_revision', String(state.publishedRevision || 0));
	state.sandboxRunning = true;
	if (state.sandboxResult) {
		state.sandboxResult.hidden = false;
		state.sandboxResult.setAttribute('data-status', 'running');
		state.sandboxResult.textContent = 'Running a side-effect-free simulation...';
	}
	updateSubmissionInboxPublishingState(state);

	submissionInboxPublishingRequest(ajax.url || window.ajaxurl, body)
		.then(function (data) {
			var effects = data.side_effects || {};
			if (!state.sandboxResult) {
				return;
			}
			state.sandboxResult.hidden = false;
			state.sandboxResult.setAttribute('data-status', data.passed ? 'pass' : 'fail');
			state.sandboxResult.innerHTML = '<strong>' +
				escapeSubmissionInboxPublishingHtml(data.message || '') +
				'</strong><p>' +
				escapeSubmissionInboxPublishingHtml(
					String(data.field_count || 0) + ' fields checked. Side effects: ' +
					String(effects.leads_created || 0) + ' leads, ' +
					String(effects.emails_sent || 0) + ' emails, ' +
					String(effects.jobs_queued || 0) + ' jobs.'
				) +
				'</p>';
		})
		.catch(function (error) {
			if (!state.sandboxResult) {
				return;
			}
			state.sandboxResult.hidden = false;
			state.sandboxResult.setAttribute('data-status', 'fail');
			state.sandboxResult.textContent = error.message || 'Safe simulation could not run.';
		})
		.finally(function () {
			state.sandboxRunning = false;
			updateSubmissionInboxPublishingState(state);
		});
}

function restoreSubmissionInboxDraftRevision(state, revision) {
	var ajax;
	var body;

	if (!state || state.publishing || !/^\d+$/.test(String(revision || ''))) {
		return;
	}
	ajax = state.formData.ajax || {};
	body = new window.URLSearchParams();
	body.set('action', ajax.restore_action || 'subin_restore_grapesjs_revision');
	body.set('form_id', String(state.formData.id || ''));
	body.set('nonce', ajax.restore_nonce || '');
	body.set('target_revision', String(revision));
	body.set('revision', String(state.revision || 0));
	body.set('published_revision', String(state.publishedRevision || 0));
	state.publishing = true;
	setSubmissionInboxPublishStatus(state, 'Restoring revision as a draft...', '');
	updateSubmissionInboxPublishingState(state);

	submissionInboxPublishingRequest(ajax.url || window.ajaxurl, body)
		.then(function (data) {
			if (data.project && typeof data.project === 'object') {
				applySubmissionInboxCanonicalProject(state.editor, data.project, state.formData, state);
			}
			setSubmissionInboxRevision(state, data.revision);
			state.publishedRevision = Math.max(0, parseInt(data.published_revision || 0, 10) || 0);
			state.publishedDirty = !!data.is_dirty;
			state.formData.is_dirty = state.publishedDirty;
			invalidateSubmissionInboxPreflight(state);
			state.changeVersion++;
			state.savedVersion = state.changeVersion;
			if (state.editor.clearDirtyCount) {
				state.editor.clearDirtyCount();
			}
			setGrapesJSSaveState(state, 'saved', 'Revision restored as a saved draft');
			setSubmissionInboxPublishStatus(state, data.message || 'Revision restored as a draft.', 'success');
		})
		.catch(function (error) {
			setSubmissionInboxPublishStatus(state, error.message || 'Revision could not be restored.', 'error');
		})
		.finally(function () {
			state.publishing = false;
			updateSubmissionInboxPublishingState(state);
		});
}

function submissionInboxPublishingRequest(url, body) {
	return window.fetch(url, {
		method: 'POST',
		credentials: 'same-origin',
		headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
		body: body.toString(),
	}).then(function (response) {
		return grapesJSResponsePayload(response).then(function (payload) {
			var data = grapesJSAjaxData(payload);
			if (!response.ok || !payload || payload.success !== true) {
				throw grapesJSSaveError(response, payload);
			}
			return data;
		});
	});
}

function renderSubmissionInboxPublishingHistory(state) {
	var items;

	if (!state.historyHost) {
		return;
	}
	items = [{
		revision: state.publishedRevision,
		published_at: state.publishedAt,
		current: true,
	}].concat((state.history || []).slice().reverse());
	state.historyHost.innerHTML = items.map(function (item) {
		var revision = Math.max(0, parseInt(item.revision || 0, 10) || 0);
		var label = item.current ? 'Current published version' : 'Published revision ' + revision;
		var action = item.current
			? '<span class="subin-studio-revision-badge">Current</span>'
			: '<button type="button" class="button button-small" data-subin-restore-revision="' + revision + '">Restore as draft</button>';
		return '<div class="subin-studio-revision-item"><div><strong>' + label + '</strong><small>' +
			escapeSubmissionInboxPublishingHtml(formatSubmissionInboxPublishedAt(item.published_at)) +
			'</small></div>' + action + '</div>';
	}).join('');
}

function formatSubmissionInboxPublishedAt(value) {
	var date = value ? new Date(value) : null;
	return date && !isNaN(date.getTime()) ? date.toLocaleString() : 'Not published yet';
}

function escapeSubmissionInboxPublishingHtml(value) {
	var node = document.createElement('span');
	node.textContent = String(value || '');
	return node.innerHTML;
}

function setSubmissionInboxPublishStatus(state, message, type) {
	if (!state.publishStatus) {
		return;
	}
	state.publishStatus.textContent = message || '';
	state.publishStatus.setAttribute('data-status', type || '');
}
