/**
 * Custom Fields conditional logic on edit screens.
 */
(function ($) {
	'use strict';

	function parseConditional($field) {
		var raw = $field.attr('data-cf-conditional');
		if (!raw) {
			return null;
		}
		try {
			return JSON.parse(raw);
		} catch (e) {
			return null;
		}
	}

	function fieldValue($box, fieldKey) {
		var $target = $box.find('[data-cf-field-key="' + fieldKey + '"]');
		if (!$target.length) {
			return '';
		}

		var $map = $target.find('.cf-google-map-field').first();
		if ($map.length) {
			var address = String($map.find('input[name$="[address]"]').val() || '').trim();
			var lat = String($map.find('input[name$="[lat]"]').val() || '').trim();
			var lng = String($map.find('input[name$="[lng]"]').val() || '').trim();
			return address || (lat && lng ? lat + ',' + lng : '');
		}

		var $checkboxes = $target.find('input[type="checkbox"]');
		var $checked = $checkboxes.filter(':checked');
		if ($checkboxes.length === 1) {
			return $checked.length ? '1' : '0';
		}
		if ($checked.length) {
			return $checked.map(function () {
				return $(this).val();
			}).get();
		}

		var $radio = $target.find('input[type="radio"]:checked').first();
		if ($radio.length) {
			return $radio.val() || '';
		}

		var $multi = $target.find('select[multiple]').first();
		if ($multi.length) {
			return $multi.val() || [];
		}

		var $input = $target.find('input, select, textarea').filter(function () {
			var type = String($(this).attr('type') || '').toLowerCase();
			return type !== 'checkbox' && type !== 'radio';
		}).first();

		if (!$input.length) {
			return '';
		}

		return $input.val() || '';
	}

	function compare(actual, operator, expected) {
		expected = String(expected || '').trim();

		if (Array.isArray(actual)) {
			var items = actual.map(function (item) {
				return String(item || '').trim();
			}).filter(function (item) {
				return item !== '';
			});

			switch (operator) {
				case '!=':
					return items.indexOf(expected) === -1;
				case 'contains':
					return expected !== '' && items.indexOf(expected) !== -1;
				case 'not_contains':
					return expected === '' || items.indexOf(expected) === -1;
				case 'empty':
					return items.length === 0;
				case 'not_empty':
					return items.length > 0;
				case '==':
					return items.indexOf(expected) !== -1;
				default:
					actual = items.join(',');
					break;
			}
		}

		actual = String(actual || '').trim();
		var a = parseFloat(actual);
		var b = parseFloat(expected);
		var numeric = !isNaN(a) && !isNaN(b);
		var actualItems = actual.split(',').map(function (item) {
			return item.trim();
		});

		function containsExpected() {
			if (expected === '') {
				return false;
			}

			return actualItems.length > 1
				? actualItems.indexOf(String(expected)) !== -1
				: String(actual).indexOf(expected) !== -1;
		}

		switch (operator) {
			case '!=':
				return actual !== expected;
			case '>':
				return numeric && a > b;
			case '>=':
				return numeric && a >= b;
			case '<':
				return numeric && a < b;
			case '<=':
				return numeric && a <= b;
			case 'contains':
				return containsExpected();
			case 'not_contains':
				return expected === '' || !containsExpected();
			case 'empty':
				return actual === '' || actual === '0';
			case 'not_empty':
				return actual !== '' && actual !== '0';
			case '==':
			default:
				return actual === expected;
		}
	}

	function matchesConditional(conditional, values) {
		if (!conditional || !conditional.enabled || !conditional.rules || !conditional.rules.length) {
			return true;
		}
		var results = conditional.rules.map(function (rule) {
			var actual = Object.prototype.hasOwnProperty.call(values, rule.field) ? values[rule.field] : '';
			return compare(actual, rule.operator || '==', rule.value || '');
		});
		return conditional.match === 'any'
			? results.indexOf(true) !== -1
			: results.indexOf(false) === -1;
	}

	function refreshBox($box) {
		var values = {};
		$box.find('[data-cf-field-key]').each(function () {
			var key = $(this).attr('data-cf-field-key');
			if (key) {
				values[key] = fieldValue($box, key);
			}
		});

		$box.find('[data-cf-field-key]').each(function () {
			var $field = $(this);
			var conditional = parseConditional($field);
			var visible = matchesConditional(conditional, values);
			$field.toggle(visible);
			if (!conditional) {
				return;
			}
			$field.find('input, select, textarea, button').each(function () {
				var $control = $(this);
				if (!$control.data('cfConditionalStateStored')) {
					$control.data('cfConditionalStateStored', true);
					$control.data('cfWasRequired', $control.prop('required'));
					$control.data('cfWasDisabled', $control.prop('disabled'));
				}
				if ($control.prop('required') && !$control.data('cfWasRequired')) {
					$control.data('cfWasRequired', true);
				}
				if (!visible) {
					$control.prop('required', false).prop('disabled', true);
					return;
				}
				$control.prop('disabled', $control.data('cfWasDisabled'));
				if ($control.data('cfWasRequired')) {
					$control.prop('required', true);
				}
			});
		});
	}

	$(function () {
		$('.cf-meta-box').each(function () {
			var $box = $(this);
			refreshBox($box);
			$box.on(
				'change input',
				'input, select, textarea',
				function () {
					refreshBox($box);
				}
			);
		});
	});
})(jQuery);
