define([
    'jquery',
    'mage/utils/wrapper'
], function ($, wrapper) {
    'use strict';

    var FIELD_SELECTOR = '[name*="postcode"]';
    var NEXT_SELECTOR = [
        '.checkout-shipping-method .action.continue',
        '.button.action.continue.primary',
        '.checkout-shipping-method button.continue',
        '.checkout-shipping-method .actions-toolbar button',
        'button[data-role="opc-continue"]'
    ].join(', ');
    var FIELD_MESSAGE_CLASS = 'portalpeople-disabled-postcode-message';
    var CHECKOUT_MESSAGE_CLASS = 'portalpeople-disabled-postcode-checkout-message';
    var MAX_PLACE_RETRIES = 12;

    function isBlockedPostcodeMessage(message) {
        var normalized = (message || '').toLowerCase();

        return normalized.indexOf('deliver to this area') !== -1 ||
            normalized.indexOf('do not deliver') !== -1 ||
            (normalized.indexOf('postcode') !== -1 &&
                normalized.indexOf('checkout') !== -1);
    }

    function normalize(postcode) {
        if (!postcode) {
            return '';
        }

        return String(postcode)
            .toUpperCase()
            .replace(/\s+/g, '')
            .replace(/[^A-Z0-9]/g, '');
    }

    function getNestedMessage(payload) {
        if (!payload) {
            return '';
        }

        if (payload.message) {
            return payload.message;
        }

        if (payload.parameters && payload.parameters.message) {
            return payload.parameters.message;
        }

        return '';
    }

    function extractResponseMessage(response) {
        var parsed;

        if (response && response.responseJSON) {
            parsed = getNestedMessage(response.responseJSON);
            if (parsed) {
                return parsed;
            }
        }

        if (response && response.responseText) {
            try {
                parsed = JSON.parse(response.responseText);
                return getNestedMessage(parsed);
            } catch (error) {
                return '';
            }
        }

        return '';
    }

    function getBlockedMessageFromConfig() {
        var config = window.checkoutConfig && window.checkoutConfig.portalpeopleDisabledPostcodes;
        var postcode = normalize($(FIELD_SELECTOR).first().val());
        var message;

        if (!config || !config.enabled || !postcode) {
            return null;
        }

        if (Array.isArray(config.exact) && config.exact.indexOf(postcode) !== -1) {
            message = config.message || 'We are sorry, we do not deliver to this area.';
            return message;
        }

        if (Array.isArray(config.areas)) {
            for (var i = 0; i < config.areas.length; i++) {
                if (config.areas[i] && postcode.indexOf(normalize(config.areas[i])) === 0) {
                    message = config.message || 'We are sorry, we do not deliver to this area.';
                    return message;
                }
            }
        }

        return null;
    }

    function placeCheckoutMessage(message) {
        var $field = $(FIELD_SELECTOR).first();
        var $container = $field.closest('.field');
        var $fieldMsg = $('.' + FIELD_MESSAGE_CLASS);
        var $next = $(NEXT_SELECTOR);
        var $checkoutMsg = $('.' + CHECKOUT_MESSAGE_CLASS);
        var $anchor = $next.first().closest('.actions-toolbar');
        var placed = false;

        if (!$anchor.length) {
            $anchor = $('.checkout-shipping-method');
        }

        if ($field.length) {
            $field.addClass('mage-error').attr('aria-invalid', 'true');
        }

        if (!$fieldMsg.length && $container.length) {
            $('<div/>', {
                'class': 'portalpeople-postcode-error ' + FIELD_MESSAGE_CLASS,
                text: message
            }).appendTo($container);
            placed = true;
        } else {
            if ($fieldMsg.length) {
                $fieldMsg.text(message).show();
                placed = true;
            }
        }

        if (!$checkoutMsg.length && $anchor.length) {
            $('<div/>', {
                'class': 'portalpeople-postcode-error portalpeople-postcode-error-checkout ' + CHECKOUT_MESSAGE_CLASS,
                text: message
            }).prependTo($anchor);
            placed = true;
        } else {
            if ($checkoutMsg.length) {
                $checkoutMsg.text(message).show();
                placed = true;
            }
        }

        return placed;
    }

    function placeCheckoutMessageWithRetry(message, attempt, onFail) {
        var retryCount = attempt || 0;

        if (placeCheckoutMessage(message)) {
            return;
        }

        if (retryCount >= MAX_PLACE_RETRIES) {
            if (typeof onFail === 'function') {
                onFail();
            }
            return;
        }

        setTimeout(function () {
            placeCheckoutMessageWithRetry(message, retryCount + 1, onFail);
        }, 150);
    }

    return function (target) {
        target.process = wrapper.wrap(target.process, function (originalProcess, response, messageContainer) {
            var detectedMessage = null;
            var extractedMessage = extractResponseMessage(response);

            try {
                if (isBlockedPostcodeMessage(extractedMessage)) {
                    detectedMessage = extractedMessage;
                } else {
                    detectedMessage = getBlockedMessageFromConfig();
                }
            } catch (error) {
                // Ignore parse errors and preserve default Magento error handling.
            }

            if (detectedMessage) {
                placeCheckoutMessageWithRetry(detectedMessage, 0, function () {
                    originalProcess(response, messageContainer);
                });
                return;
            }

            originalProcess(response, messageContainer);
        });

        return target;
    };
});
