define([
    'jquery',
    'Magento_Checkout/js/model/quote',
    'PortalPeople_DisabledPostcodes/js/model/postcode-validator'
], function ($, quote, postcodeValidator) {
    'use strict';

    var HIDDEN_BY_MODULE_CLASS = 'portalpeople-disabled-postcode-hidden';
    var NEXT_BUTTON_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 SHIPPING_FIELDS_SELECTOR = [
        '.fieldset.shipping-information',
        '.delivery-information',
        '.field.delivery-date',
        '.field.what3words',
        '.field.shipping-instructions'
    ].join(', ');
    var CHECKOUT_MESSAGE_CLASS = 'portalpeople-disabled-postcode-checkout-message';

    function getContinueButtons() {
        var $buttons = $(NEXT_BUTTON_SELECTOR);
        var $textButtons = $('.checkout-shipping-method button').filter(function () {
            var text = $(this).text().trim().toLowerCase();
            return text === 'next' || text === 'continue';
        });

        return $buttons.add($textButtons);
    }

    function getCurrentPostcodeFromForm() {
        var value = $('[name*="postcode"]').first().val();
        return value || '';
    }

    function getConfig() {
        if (window.checkoutConfig && window.checkoutConfig.portalpeopleDisabledPostcodes) {
            return window.checkoutConfig.portalpeopleDisabledPostcodes;
        }
        return {enabled: false, exact: [], areas: [], message: ''};
    }

    function applyUiState(isBlocked, message) {
        var $button = getContinueButtons();
        var $shippingFields = $(SHIPPING_FIELDS_SELECTOR);
        var $container = $('[name*="postcode"]').first().closest('.field');
        var $existing = $('.portalpeople-disabled-postcode-message');
        var $checkoutExisting = $('.' + CHECKOUT_MESSAGE_CLASS);
        var $postcodeInput = $('[name*="postcode"]').first();
        var $buttonAnchor = $button.first().closest('.actions-toolbar');

        if (!$buttonAnchor.length && $button.length) {
            $buttonAnchor = $button.first().parent();
        }
        if (!$buttonAnchor.length) {
            $buttonAnchor = $('.checkout-shipping-method');
        }

        if (isBlocked) {
            $('body').removeClass('portalpeople-postcode-blocked');
            $button
                .addClass(HIDDEN_BY_MODULE_CLASS)
                .prop('disabled', true)
                .attr('aria-disabled', 'true')
                .show();

            $shippingFields.show();
            $postcodeInput.addClass('mage-error').attr('aria-invalid', 'true');

            if (!$existing.length && $container.length) {
                $('<div/>', {
                    'class': 'message error portalpeople-disabled-postcode-message',
                    text: message
                }).appendTo($container);
            } else {
                $existing.text(message).show();
            }

            if (!$checkoutExisting.length && $buttonAnchor.length) {
                $('<div/>', {
                    'class': 'message error ' + CHECKOUT_MESSAGE_CLASS,
                    text: message + ' Please change your postcode to continue checkout.'
                }).appendTo($buttonAnchor);
            } else {
                $checkoutExisting
                    .text(message + ' Please change your postcode to continue checkout.')
                    .show();
            }
        } else {
            $('body').removeClass('portalpeople-postcode-blocked');
            $button
                .filter('.' + HIDDEN_BY_MODULE_CLASS)
                .prop('disabled', false)
                .removeAttr('aria-disabled')
                .removeClass(HIDDEN_BY_MODULE_CLASS)
                .show();
            $shippingFields.show();
            $postcodeInput.removeClass('mage-error').removeAttr('aria-invalid');
            $existing.remove();
            $checkoutExisting.remove();
        }
    }

    return function (targetComponent) {
        return targetComponent.extend({
            initialize: function () {
                this._super();

                var self = this;

                function evaluate(postcode) {
                    var config = getConfig();
                    var isBlocked = postcodeValidator.isExcluded(postcode, config);
                    applyUiState(isBlocked, config.message || 'We are sorry, we do not deliver to this area.');
                }

                function evaluateFromForm() {
                    evaluate(getCurrentPostcodeFromForm());
                }

                // Handle direct typing in postcode field.
                $(document)
                    .off('.portalpeopleDisabledPostcodes')
                    .on('input.portalpeopleDisabledPostcodes change.portalpeopleDisabledPostcodes blur.portalpeopleDisabledPostcodes', '[name*="postcode"]', function () {
                    evaluate($(this).val());
                });

                // Re-apply after checkout async refreshes that can re-render shipping nodes.
                $(document)
                    .on('updated_checkout.portalpeopleDisabledPostcodes ajaxComplete.portalpeopleDisabledPostcodes', function () {
                        evaluateFromForm();
                    });

                // Handle address object changes after autofill/address select.
                quote.shippingAddress.subscribe(function (address) {
                    var postcode = address && address.postcode ? address.postcode : getCurrentPostcodeFromForm();
                    evaluate(postcode);
                });

                // Initial check when shipping component loads.
                var currentAddress = quote.shippingAddress();
                evaluate(currentAddress && currentAddress.postcode ? currentAddress.postcode : getCurrentPostcodeFromForm());

                // Small delayed re-check catches KO render cycles after field blur/change.
                setTimeout(evaluateFromForm, 250);
                setTimeout(evaluateFromForm, 800);

                // Keep state in sync during shipping-step async rerenders.
                if (window.portalpeopleDisabledPostcodesIntervalId) {
                    clearInterval(window.portalpeopleDisabledPostcodesIntervalId);
                }
                window.portalpeopleDisabledPostcodesIntervalId = setInterval(function () {
                    evaluateFromForm();
                }, 700);

                return self;
            }
        });
    };
});
