/**
 * Simply.IN Pickup Point Integration Manager
 * Handles integration between SimplyIN popup parcel locker selection and Magento shipping modules.
 * Processes parcel locker selections, normalizes provider names, and sets extension attributes
 * via backend API calls. Also calls native module endpoints to update their UI.
 */
define([
    'jquery',
    'Magento_Checkout/js/model/shipping-service',
    'Simplyin_Payment/js/model/ajax-client'
], function ($, shippingService, ajaxClient) {
    'use strict';

    return {
        /**
         * Provider name mappings to identify which native module to call
         */
        PROVIDER_INPOST: ['inpost', 'paczkomaty', 'inpostlocker'],
        PROVIDER_ORLEN: ['orlen', 'orlenpaczka', 'ruch'],
        PROVIDER_DPD: ['dpd', 'dpdpickup', 'dpdparcelshop'],
        PROVIDER_DHL: ['dhl', 'dhlparcel', 'dhlservicepoint'],
        PROVIDER_UPS: ['ups', 'upsaccesspoint'],
        /**
         * Get provider name from locker data (normalized to lowercase)
         * Extracts provider name from `providerName` or `provider` field
         * 
         * @param {Object} lockerData - Complete parcel locker data from SimplyIN
         * @returns {string} - Normalized provider name (lowercase) or empty string if not found
         * 
         * Requirements: 1.1, 1.2
         */
        getProviderName: function (lockerData) {
            if (!lockerData) {
                console.warn('SimplyIn Integration: No locker data provided');
                return '';
            }

            // Extract provider name from providerName or provider field (Requirement 1.1)
            var providerName = lockerData.providerName || lockerData.provider || '';

            // Normalize to lowercase (Requirement 1.2)
            var normalizedName = String(providerName).toLowerCase().trim();

            if (!normalizedName) {
                console.warn('SimplyIn Integration: No provider name found in locker data');
            }

            return normalizedName;
        },

        /**
         * Build parcel locker minimal info for API
         * Creates the minimal info object containing lockerId and providerName
         * 
         * @param {Object} lockerData - Complete parcel locker data from SimplyIN
         * @returns {Object} - {lockerId: string, providerName: string}
         * 
         * Requirements: 6.1, 6.2
         */
        buildParcelLockerMinimalInfo: function (lockerData) {
            if (!lockerData) {
                console.warn('SimplyIn Integration: Cannot build minimal info - no locker data');
                return {
                    lockerId: '',
                    providerName: ''
                };
            }

            var lockerId = String(lockerData.lockerId || '');
            var providerName = this.getProviderName(lockerData);

            return {
                lockerId: lockerId,
                providerName: providerName
            };
        },

        /**
         * Set extension attributes via AJAX call to backend
         * Makes POST request to simplyin/api/setpickuppoint endpoint
         * 
         * @param {string} providerName - Normalized provider name
         * @param {Object} lockerData - Complete parcel locker data
         * @returns {Promise} - jQuery Deferred promise with success/error result
         * 
         * Requirements: 8.5, 9.1
         */
        setExtensionAttributes: function (providerName, lockerData) {
            var deferred = $.Deferred();

            // Get quoteId from Magento checkout config
            var quoteId = this._getQuoteId();

            if (!quoteId) {
                console.error('SimplyIn Integration: Cannot set extension attributes - no quote ID');
                deferred.reject({
                    success: false,
                    message: 'No quote ID available'
                });
                return deferred.promise();
            }

            if (!providerName) {
                console.warn('SimplyIn Integration: No provider name - skipping extension attributes');
                // Return success but indicate no integration was performed
                deferred.resolve({
                    success: true,
                    message: 'No provider name - skipped module integration',
                    skipped: true
                });
                return deferred.promise();
            }

            var lockerId = lockerData.lockerId || '';

            if (!lockerId) {
                console.warn('SimplyIn Integration: No locker ID - skipping extension attributes');
                deferred.resolve({
                    success: true,
                    message: 'No locker ID - skipped module integration',
                    skipped: true
                });
                return deferred.promise();
            }

            // Build request payload
            var payload = {
                quoteId: quoteId,
                providerName: providerName,
                lockerId: lockerId,
                lockerData: lockerData
            };

            // Make POST to backend API via ajax-client
            ajaxClient.post('simplyin/api/setpickuppoint', payload)
                .done(function (response) {
                    deferred.resolve({
                        success: true,
                        message: response.message || 'Extension attributes set successfully',
                        data: response
                    });
                })
                .fail(function (jqXHR, textStatus, errorThrown) {
                    console.error('SimplyIn Integration: Failed to set extension attributes', {
                        status: textStatus,
                        error: errorThrown,
                        response: jqXHR
                    });

                    var errorMessage = 'Failed to set extension attributes';
                    var body = jqXHR && jqXHR.responseJSON ? jqXHR.responseJSON : null;
                    if (body && body.message) {
                        errorMessage = body.message;
                    }

                    deferred.reject({
                        success: false,
                        message: errorMessage,
                        error: jqXHR
                    });
                });

            return deferred.promise();
        },

        /**
         * Check if provider matches InPost
         * @param {string} providerName - Normalized provider name
         * @returns {boolean}
         */
        isInpostProvider: function (providerName) {
            return this.PROVIDER_INPOST.some(function (name) {
                return providerName.indexOf(name) !== -1;
            });
        },

        /**
         * Check if provider matches Orlen
         * @param {string} providerName - Normalized provider name
         * @returns {boolean}
         */
        isOrlenProvider: function (providerName) {
            return this.PROVIDER_ORLEN.some(function (name) {
                return providerName.indexOf(name) !== -1;
            });
        },

        /**
         * Check if provider matches DPD
         * @param {string} providerName - Normalized provider name
         * @returns {boolean}
         */
        isDpdProvider: function (providerName) {
            return this.PROVIDER_DPD.some(function (name) {
                return providerName.indexOf(name) !== -1;
            });
        },

        /**
         * Call InPost's native save endpoint to update their UI
         * @param {string} lockerId - The locker/point ID
         * @param {Object} lockerData - Complete locker data (optional, for UI display)
         * @returns {Promise}
         */
        callInpostNativeSave: function (lockerId, lockerData) {
            var deferred = $.Deferred();
            var baseUrl = this._getBaseUrl();

            $.ajax({
                type: 'POST',
                url: baseUrl + '/inpost/locker/save',
                data: {
                    'inpost_locker_id': lockerId
                },
                dataType: 'json'
            }).done(function (data) {
                if (data && data.status === 1) {
                    // Update the checkoutConfig so InPost UI can read the new value
                    if (window.checkoutConfig && window.checkoutConfig.quoteData) {
                        window.checkoutConfig.quoteData.inpost_locker_id = lockerId;
                    }
                    
                    // Update the InPost UI to show selected point instead of "Please select a pickup point"
                    setTimeout(function () {
                        // Find InPost wrapper and update it
                        var inpostWrapper = $('[data-inpost-wrapper]');
                        if (inpostWrapper.length && lockerData) {
                            var pointInfo = lockerData.name || lockerData.lockerId || lockerId;
                            var addressInfo = '';
                            if (lockerData.street || lockerData.addressLine) {
                                addressInfo = (lockerData.street || lockerData.addressLine);
                                if (lockerData.city) {
                                    addressInfo += ', ' + lockerData.city;
                                }
                            }
                            
                            // Create display HTML similar to InPost's native format
                            var displayHtml = '<div data-inpost-point-data class="point-data">' +
                                '<p>Wybrany punkt odbioru:</p>' +
                                '<p>' + pointInfo;
                            if (addressInfo) {
                                displayHtml += ' | ' + addressInfo;
                            }
                            displayHtml += '</p></div>';
                            displayHtml += '<button data-inpost-select-point class="action secondary small" title="Zmień punkt odbioru">Zmień punkt odbioru</button>';
                            
                            // Update the wrapper content
                            inpostWrapper.html(displayHtml);
                        }
                    }, 200);
                    
                    deferred.resolve({ success: true });
                } else {
                    console.warn('SimplyIn Integration: InPost native save returned non-success', data);
                    deferred.resolve({ success: false, data: data });
                }
            }).fail(function (xhr, status, error) {
                console.error('SimplyIn Integration: InPost native save failed', error);
                deferred.resolve({ success: false, error: error });
            });

            return deferred.promise();
        },

        /**
         * Call Orlen's native save endpoint to update their UI
         * Directly saves the pickup point without opening the Orlen map popup
         * @param {Object} lockerData - Complete locker data with address info
         * @returns {Promise}
         */
        callOrlenNativeSave: function (lockerData) {
            var deferred = $.Deferred();
            var self = this;
            var baseUrl = this._getBaseUrl();
            var lockerId = lockerData.lockerId || '';

            // Build description from locker data
            var description = this._buildOrlenDescription(lockerData);
            // destination_code should be the lockerId (e.g., "WS-113722-A9-24")
            // Also check for destinationCode field from Orlen's native format
            var destinationCode = lockerData.destinationCode || lockerId;

            $.ajax({
                type: 'POST',
                url: baseUrl + '/orlenshipping/point/save',
                data: {
                    'description': description,
                    'destination_code': destinationCode
                },
                dataType: 'json'
            }).done(function (data) {
                if (data && data.type === 'success') {
                    // Get quote ID for cache
                    var quoteId = self._getQuoteId();
                    
                    // Build complete Orlen data object matching native format
                    var orlenData = {
                        selectedPoint: lockerId,
                        pointDescription: description,
                        destinationCode: destinationCode,
                        quoteId: quoteId
                    };
                    
                    // Update Orlen's local storage cache (matching native format)
                    try {
                        if (window.localStorage) {
                            var cacheStorage = JSON.parse(window.localStorage.getItem('mage-cache-storage') || '{}');
                            cacheStorage['orlen-data'] = orlenData;
                            window.localStorage.setItem('mage-cache-storage', JSON.stringify(cacheStorage));
                        }
                    } catch (e) {
                        console.warn('SimplyIn Integration: Could not update Orlen localStorage cache', e);
                    }
                    
                    // Update customer data section for Orlen (critical for validation)
                    try {
                        require(['Magento_Customer/js/customer-data'], function (customerData) {
                            customerData.set('orlen-data', orlenData);
                        });
                    } catch (e) {
                        console.warn('SimplyIn Integration: Could not update Orlen customer data', e);
                    }
                    
                    // Update the Orlen UI to show selected point instead of "Choose pick-up point"
                    setTimeout(function () {
                        var orlenButton = $('.orlen-shipping-button');
                        if (orlenButton.length) {
                            var pointInfo = lockerData.name || lockerData.groupName || lockerId;
                            var addressInfo = '';
                            if (lockerData.street || lockerData.addressLine) {
                                addressInfo = (lockerData.street || lockerData.addressLine);
                                if (lockerData.city) {
                                    addressInfo += ', ' + lockerData.city;
                                }
                            }
                            
                            var displayHtml = '<div class="simplyin-orlen-selected-point" style="padding: 10px; background: #f5f5f5; border-radius: 4px; margin-top: 5px;">' +
                                '<strong>' + pointInfo + '</strong>';
                            if (addressInfo) {
                                displayHtml += '<br><small>' + addressInfo + '</small>';
                            }
                            displayHtml += '</div>';
                            
                            orlenButton.hide();
                            orlenButton.siblings('.simplyin-orlen-selected-point').remove();
                            orlenButton.after(displayHtml);
                        }
                    }, 300);
                    
                    deferred.resolve({ success: true });
                } else {
                    console.warn('SimplyIn Integration: Orlen native save returned non-success', data);
                    deferred.resolve({ success: false, data: data });
                }
            }).fail(function (error) {
                console.error('SimplyIn Integration: Orlen native save failed', error);
                deferred.resolve({ success: false, error: error });
            });

            return deferred.promise();
        },

        /**
         * Build Orlen description string from locker data
         * Format matches Orlen's native format: "groupName, \naddressLine, city postalCode"
         * Handles both Orlen's native format and SimplyIN's format
         * @private
         * @param {Object} lockerData
         * @returns {string}
         */
        _buildOrlenDescription: function (lockerData) {
            // Match Orlen's native format:
            // `${pointData?.groupName ?? ''}, \n${pointData?.addressLine ?? ''}, ${pointData?.city ?? ''} ${pointData?.postalCode ?? ''}`
            
            // Try Orlen's native field names first, then fall back to SimplyIN's field names
            var groupName = lockerData.groupName || lockerData.addressName || lockerData.name || lockerData.label || '';
            var addressLine = lockerData.addressLine || lockerData.address || lockerData.street || '';
            var city = lockerData.city || '';
            var postalCode = lockerData.postalCode || lockerData.postcode || lockerData.zipCode || '';
            
            // If we have a combined address but no separate city/postalCode, try to parse it
            if (addressLine && !city && addressLine.includes(',')) {
                var parts = addressLine.split(',');
                if (parts.length >= 2) {
                    addressLine = parts[0].trim();
                    // Try to extract city and postal code from remaining parts
                    var remaining = parts.slice(1).join(',').trim();
                    // Check if remaining contains postal code pattern (XX-XXX)
                    var postalMatch = remaining.match(/(\d{2}-\d{3})/);
                    if (postalMatch) {
                        postalCode = postalMatch[1];
                        city = remaining.replace(postalCode, '').trim().replace(/^,|,$/g, '').trim();
                    } else {
                        city = remaining;
                    }
                }
            }
            
            // Build in Orlen's exact format
            var description = groupName + ', \n' + addressLine + ', ' + city + ' ' + postalCode;
            
            return description;
        },

        /**
         * Set DPD pickup point by updating the hidden input field
         * DPD has two shipping methods with separate inputs:
         * - DPD Pickup: #dpd-widget-select container with #point-wrapper input
         * - DPD SwipBox (Automaty paczkowe): #dpd-swipbox-widget-select container with #point-wrapper input
         * Both use the same input ID but in different containers
         * Then triggers setShippingInformationAction to save to quote
         * @param {string} lockerId - The pickup point ID
         * @param {Object} lockerData - Complete locker data (optional, for UI display)
         * @returns {Promise}
         */
        callDpdNativeSave: function (lockerId, lockerData) {
            var deferred = $.Deferred();
            var self = this;

            // DPD has two different shipping methods with separate containers
            // We need to set the point-wrapper input in BOTH containers if they exist
            var dpdPickupContainer = document.getElementById('dpd-widget-select');
            var dpdSwipboxContainer = document.getElementById('dpd-swipbox-widget-select');
            
            var pointWrapperSet = false;
            
            // Set value in DPD Pickup container
            if (dpdPickupContainer) {
                var pickupInput = dpdPickupContainer.querySelector('#point-wrapper, input[name="shipping_dpd_pickup"]');
                if (pickupInput) {
                    pickupInput.value = lockerId;
                    pointWrapperSet = true;
                    
                    // Update UI
                    self._updateDpdContainerUI(dpdPickupContainer, lockerId, lockerData);
                }
            }
            
            // Set value in DPD SwipBox container
            if (dpdSwipboxContainer) {
                var swipboxInput = dpdSwipboxContainer.querySelector('#point-wrapper, input[name="shipping_dpd_swipbox"]');
                if (swipboxInput) {
                    swipboxInput.value = lockerId;
                    pointWrapperSet = true;
                    
                    // Update UI
                    self._updateDpdContainerUI(dpdSwipboxContainer, lockerId, lockerData);
                }
            }
            
            // Fallback: try to find any point-wrapper input if containers not found
            if (!pointWrapperSet) {
                var allPointWrappers = document.querySelectorAll('#point-wrapper, input[name="shipping_dpd_pickup"], input[name="shipping_dpd_swipbox"]');
                allPointWrappers.forEach(function (input) {
                    input.value = lockerId;
                    pointWrapperSet = true;
                });
            }
            
            if (pointWrapperSet) {
                // Trigger setShippingInformationAction to save the extension attributes
                // This is critical because DPD's mixin reads point-wrapper value during this action
                try {
                    require([
                        'Magento_Checkout/js/action/set-shipping-information',
                        'Magento_Checkout/js/model/quote'
                    ], function (setShippingInformationAction, quote) {
                        // Only trigger if shipping method is already selected
                        if (quote.shippingMethod()) {
                            setShippingInformationAction().done(function () {
                                console.log('SimplyIn Integration: DPD shipping information saved successfully');
                            }).fail(function (error) {
                                console.warn('SimplyIn Integration: DPD setShippingInformationAction failed', error);
                            });
                        } else {
                            console.log('SimplyIn Integration: DPD - shipping method not yet selected, will save on method selection');
                        }
                    });
                } catch (e) {
                    console.warn('SimplyIn Integration: Could not trigger setShippingInformationAction', e);
                }
                
                deferred.resolve({ success: true });
            } else {
                console.warn('SimplyIn Integration: No DPD point-wrapper element found');
                deferred.resolve({ success: false, message: 'point-wrapper not found' });
            }

            return deferred.promise();
        },
        
        /**
         * Update DPD container UI to show selected point
         * @private
         * @param {HTMLElement} container - The DPD widget container
         * @param {string} lockerId - The pickup point ID
         * @param {Object} lockerData - Complete locker data
         */
        _updateDpdContainerUI: function (container, lockerId, lockerData) {
            if (!container || !lockerData) {
                return;
            }
            
            var pointInfo = lockerData.name || lockerData.addressName || lockerData.groupName || lockerId;
            var addressInfo = '';
            if (lockerData.address || lockerData.street || lockerData.addressLine) {
                addressInfo = lockerData.address || lockerData.street || lockerData.addressLine;
                if (lockerData.city) {
                    addressInfo += ', ' + lockerData.city;
                }
            }
            
            // Remove existing display
            var existingDisplay = container.querySelector('.simplyin-dpd-selected-point');
            if (existingDisplay) {
                existingDisplay.remove();
            }
            
            // Add visual indicator of selected point
            var displayHtml = document.createElement('div');
            displayHtml.className = 'simplyin-dpd-selected-point';
            displayHtml.style.cssText = 'padding: 10px; background: #f5f5f5; border-radius: 4px; margin-top: 5px;';
            displayHtml.innerHTML = '<strong>' + pointInfo + '</strong>' + 
                (addressInfo ? '<br><small>' + addressInfo + '</small>' : '');
            container.appendChild(displayHtml);
        },

        /**
         * Trigger shipping rates reload to refresh UI
         * This causes the shipping method UI components to re-render
         * @param {string} providerName - The provider name to determine which module to refresh
         */
        triggerShippingRatesReload: function (providerName) {
            var self = this;
            
            // Trigger isLoading to force UI refresh
            if (shippingService && shippingService.isLoading) {
                // Set loading to true then false to trigger subscribers
                shippingService.isLoading(true);
                setTimeout(function () {
                    shippingService.isLoading(false);
                    
                    // Only trigger InPost render for InPost providers
                    if (providerName && self.isInpostProvider(providerName)) {
                        self._triggerInpostRender();
                    }
                    
                    // Safety: Ensure fullScreenLoader is stopped after a delay
                    // This handles cases where InPost module fails or point not found
                    setTimeout(function () {
                        self._ensureLoaderStopped();
                    }, 3000);
                }, 100);
            }
        },

        /**
         * Ensure fullScreenLoader is stopped
         * Safety mechanism to prevent infinite loading state
         * @private
         */
        _ensureLoaderStopped: function () {
            try {
                require(['Magento_Checkout/js/model/full-screen-loader'], function (fullScreenLoader) {
                    // Force stop the loader
                    fullScreenLoader.stopLoader(true);
                });
            } catch (e) {
                // Ignore loader stop errors
            }
        },

        /**
         * Try to trigger InPost's render method directly
         * @private
         */
        _triggerInpostRender: function () {
            try {
                // Try to require and call InPost's module with fullScreenLoader to ensure loader stops
                require([
                    'Smartmage_Inpost/js/inpost-paczkomaty',
                    'Magento_Checkout/js/model/full-screen-loader'
                ], function (inpostModule, fullScreenLoader) {
                    if (inpostModule && typeof inpostModule.renderInPostData === 'function') {
                        inpostModule.renderInPostData().then(function () {
                            // Ensure loader is stopped after render completes
                            fullScreenLoader.stopLoader();
                        }).catch(function () {
                            // Stop loader even on error
                            fullScreenLoader.stopLoader();
                        });
                    }
                });
            } catch (e) {
                // Try to stop loader anyway
                try {
                    require(['Magento_Checkout/js/model/full-screen-loader'], function (fullScreenLoader) {
                        fullScreenLoader.stopLoader();
                    });
                } catch (loaderError) {
                    // Ignore
                }
            }
        },

        /**
         * Process parcel locker selection and set module-specific data
         * Main entry point for pickup point integration
         * 
         * @param {Object} lockerData - Complete parcel locker data from SimplyIN
         * @returns {Promise<Object>} - Result with success status and any errors
         * 
         * Requirements: 1.1, 1.2, 6.1, 6.2
         */
        processParcelLockerSelection: function (lockerData) {
            var self = this;
            var deferred = $.Deferred();

            if (!lockerData) {
                console.warn('SimplyIn Integration: No locker data provided');
                deferred.resolve({
                    success: true,
                    message: 'No locker data - nothing to process',
                    skipped: true
                });
                return deferred.promise();
            }

            // Extract and normalize provider name (Requirements 1.1, 1.2)
            var providerName = this.getProviderName(lockerData);
            var lockerId = lockerData.lockerId || '';

            // Build minimal info for reference (Requirements 6.1, 6.2)
            var minimalInfo = this.buildParcelLockerMinimalInfo(lockerData);

            // Call backend API to set extension attributes
            this.setExtensionAttributes(providerName, lockerData)
                .done(function (result) {
                    // Now call native module endpoint based on provider
                    var nativePromise;
                    
                    if (self.isInpostProvider(providerName)) {
                        nativePromise = self.callInpostNativeSave(lockerId, lockerData);
                    } else if (self.isOrlenProvider(providerName)) {
                        nativePromise = self.callOrlenNativeSave(lockerData);
                    } else if (self.isDpdProvider(providerName)) {
                        nativePromise = self.callDpdNativeSave(lockerId, lockerData);
                    } else {
                        // No native endpoint to call, just resolve
                        nativePromise = $.Deferred().resolve({ success: true, skipped: true }).promise();
                    }
                    
                    nativePromise.done(function (nativeResult) {
                        // Trigger shipping rates reload to refresh UI (pass provider name)
                        self.triggerShippingRatesReload(providerName);
                        
                        deferred.resolve({
                            success: true,
                            message: result.message,
                            providerName: providerName,
                            minimalInfo: minimalInfo,
                            skipped: result.skipped || false,
                            nativeIntegration: nativeResult
                        });
                    });
                })
                .fail(function (error) {
                    console.error('SimplyIn Integration: Processing failed', error);
                    // Even on failure, we resolve (not reject) to allow order to proceed
                    // The error is logged and can be handled by the caller
                    deferred.resolve({
                        success: false,
                        message: error.message,
                        providerName: providerName,
                        minimalInfo: minimalInfo,
                        error: error
                    });
                });

            return deferred.promise();
        },

        /**
         * Get quote ID from Magento checkout configuration
         * @private
         * @returns {string|null} - Quote entity ID or null if not available
         */
        _getQuoteId: function () {
            try {
                if (window.checkoutConfig && 
                    window.checkoutConfig.quoteData && 
                    window.checkoutConfig.quoteData.entity_id) {
                    return window.checkoutConfig.quoteData.entity_id;
                }
            } catch (e) {
                console.error('SimplyIn Integration: Error getting quote ID', e);
            }
            return null;
        },

        /**
         * Get base URL from Magento checkout configuration
         * @private
         * @returns {string} - Base URL without trailing slash
         */
        _getBaseUrl: function () {
            var baseUrl = '';
            try {
                if (window.checkoutConfig && window.checkoutConfig.base_url) {
                    baseUrl = window.checkoutConfig.base_url.replace(/\/$/, '');
                } else if (window.checkoutConfig && window.checkoutConfig.staticBaseUrl) {
                    // Extract base URL from static base URL
                    baseUrl = window.checkoutConfig.staticBaseUrl.replace(/\/static\/.*$/, '');
                } else if (window.BASE_URL) {
                    baseUrl = window.BASE_URL.replace(/\/$/, '');
                } else {
                    // Fallback: use current origin
                    baseUrl = window.location.origin;
                }
            } catch (e) {
                baseUrl = window.location.origin;
            }
            return baseUrl;
        },

        /**
         * Get API URL for SetPickupPoint endpoint
         * @private
         * @returns {string} - Full URL to the API endpoint
         */
        _getApiUrl: function () {
            return this._getBaseUrl() + '/simplyin/api/setpickuppoint';
        }
    };
});
