// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

// {namespace name=backend/viison_dhl_config/config}
Ext.define('Shopware.apps.ViisonDHLConfig.controller.DHLScraper', {

    extend: 'Enlight.app.Controller',

    /**
     * Important: We can't register the buttons, etc. as references, because every
     * sub-shop has his own configuration and so every component is registered/created via the sub-shop id.
     */
    refs: [
        { ref: 'panel', selector: 'viisondhlconfig-panel' },
    ],

    /**
     * @Override
     */
    init: function () {
        this.callParent(arguments);

        // Register listeners
        this.control({
            'viisondhlconfig-panel base-element-text[origName=username]': {
                change: this.onChangeCredentials,
                render: this.onChangeCredentials,
            },
            'viisondhlconfig-panel base-element-text[origName=password]': {
                change: this.onChangeCredentials,
                render: this.onChangeCredentials,
            },
            'viisondhlconfig-panel base-element-boolean[origName=useTestingWebservice]': {
                change: this.onChangeCredentials,
                render: this.onChangeCredentials,
            },
            'viisondhlconfig-panel base-element-button': {
                verifyCredentials: this.onVerifyCredentials,
                scrapData: this.onScraperDataApply,
            },
        });
    },

    /**
     * When DHL GKP username or password was changed, enable the "validate credentials" button if both are non-empty
     * and the password is not the dummy password.
     *
     * @param { base-element-text } credentialsField the credentialsField that was changed
     */
    onChangeCredentials: function (credentialsField) {
        var credentials = this.getPanel().getCredentials(credentialsField.shopId);
        var areCredentialsEmpty = !credentials.username || !credentials.password;
        var isDummyPassword = credentials.password === '************';
        var disableVerificationButton = areCredentialsEmpty || credentials.useTestingWebservice || isDummyPassword;

        var credentialsVerificationButton = credentialsField.up().down('base-element-button[action=verify]');
        var scraperDataApplyButton = credentialsField.up().down('base-element-button[action=scraperFillData]');

        // Disable buttons if credentials are invalid
        credentialsVerificationButton.setDisabled(disableVerificationButton);
        scraperDataApplyButton.setDisabled(disableVerificationButton);
    },

    /**
     * When the "verify credentials" button is clicked, ask the action to do the actual validation with DHL.
     *
     * @param { Ext.form.Button } verifyCredentialsButton
     * @param { int } shopId
     * @param { { username: string, password: string } } credentials
     */
    onVerifyCredentials: function (verifyCredentialsButton, shopId, credentials) {
        var requestParams = Ext.apply(credentials, {
            shopId: shopId,
        });

        // Lock the button, so the user can only fire one request at time
        verifyCredentialsButton.setDisabled(true);

        this.showLoginProgressBar();
        this.triggerActionForVerificationRequest(
            requestParams,
            verifyCredentialsButton,
            shopId
        );
    },

    /**
     * Inform the user about the verification progress.
     */
    showLoginProgressBar: function () {
        Ext.Msg.wait(
            '{s name="dhl_scraper/modals/connecting_gkp/message"}{/s}',
            '{s name="dhl_scraper/modals/connecting_gkp/title"}{/s}'
        );
    },

    /**
     * Resolve the action request.
     *
     * @param { object } requestParams
     * @param { Ext.form.Button } verifyCredentialsButton
     * @param { int } requestParams
     */
    triggerActionForVerificationRequest: function (requestParams, verifyCredentialsButton, shopId) {
        var endpoint = '{url controller=ViisonDHLConfig action=verifyCredentials}';
        Ext.Ajax.request({
            url: endpoint,
            params: requestParams,
            success: this.onVerifyCredentialsSuccess.bind(this),
            failure: this.onDHLScraperServerFailure.bind(this),
            eventSource: verifyCredentialsButton,
            shopId: shopId,
        });
    },

    /**
     * Handle the validation response. Note that success means we received a response at all, and does not imply
     * validation was successful.
     *
     * @param { object } response
     */
    onVerifyCredentialsSuccess: function (response) {
        var verifyCredentialsButton = response.request.options.eventSource;
        var shopId = response.request.options.shopId;

        Ext.Msg.hide();

        var result = Ext.decode(response.responseText);
        if (result.areCredentialsValid) {
            verifyCredentialsButton.setDisabled(false);
            Ext.Msg.alert(
                '{s name="dhl_scraper/modals/credentials_validated/title"}{/s}',
                '{s name="dhl_scraper/modals/credentials_validated/message"}{/s}'
            );
        } else {
            this.invalidCredentials(shopId);
        }
    },

    /**
     * When the "apply GKP data" button is clicked, ask the backend to do the actual validation & scraping with DHL.
     *
     * @param { Ext.form.Button } applyGKPDataButton
     * @param { int } shopId
     * @param { { username: string, password: string } } credentials
     */
    onScraperDataApply: function (applyGKPDataButton, shopId, credentials) {
        var requestParams = Ext.apply(credentials, {
            shopId: shopId,
        });

        // Lock the request, so the user can only fire one request at time
        applyGKPDataButton.setDisabled(true);

        this.showDataScrapingProgressBar();
        this.triggerActionForGKPDataExtractionRequest(
            requestParams,
            applyGKPDataButton,
            shopId
        );
    },

    /**
     * Inform the user about the data scraping progress from GKP.
     */
    showDataScrapingProgressBar: function () {
        Ext.Msg.wait(
            '{s name="dhl_scraper/modals/extracting_data_from_gkp/message"}{/s}',
            '{s name="dhl_scraper/modals/extracting_data_from_gkp/title"}{/s}'
        );
    },

    /**
     * Resolve the action request.
     *
     * @param { object } requestParams
     * @param { Ext.form.Button } applyGKPDataButton
     * @param { int } shopId
     */
    triggerActionForGKPDataExtractionRequest: function (requestParams, applyGKPDataButton, shopId) {
        var endpoint = '{url controller=ViisonDHLConfig action="getDataFromScraper"}';
        Ext.Ajax.request({
            url: endpoint,
            params: requestParams,
            success: this.onDHLScraperAccountDataSuccess.bind(this),
            failure: this.onDHLScraperServerFailure.bind(this),
            eventSource: applyGKPDataButton,
            shopId: shopId,
        });
    },

    /**
     * @param response
     */
    onDHLScraperAccountDataSuccess: function (response) {
        var shopId = response.request.options.shopId;
        var applyGKPDataButton = response.request.options.eventSource;
        applyGKPDataButton.setDisabled(false);

        Ext.Msg.hide();

        var result = Ext.decode(response.responseText);
        if (!result.success) {
            if (result.error_cause && this.isErrorCauseInvalidCredentials(result.error_cause)) {
                applyGKPDataButton.setDisabled(true);
                this.invalidCredentials(shopId);

                return;
            }

            Ext.Msg.alert(
                '{s name="dhl_scraper/modals/manual_validation_required/title"}{/s}',
                Ext.String.format('{s name="dhl_scraper/modals/manual_validation_required/message"}{/s}', result.message)
            );

            return;
        }

        this.mapCustomerNumberToField(this.getPanel().getEKPField(shopId), result.EKP);
        this.mapAttendanceNumbers(result.accountInformation, shopId);
        this.showGrowlMessageForMoreAttendanceNumbersIfPossible(
            this.getProductsThatHaveMoreAttendanceNumbers(result.accountInformation)
        );

        Ext.Msg.alert(
            '{s name="dhl_scraper/modals/scraper_data_fill/title"}{/s}',
            '{s name="dhl_scraper/modals/scraper_data_fill/message"}{/s}'
        );
    },

    /**
     * @param { string } errorCause
     * @return { boolean }
     */
    isErrorCauseInvalidCredentials: function (errorCause) {
        return errorCause === 'login_failed';
    },

    /**
     * Raise popup, disable button and mark the credentials as invalid.
     *
     * @param { int } shopId
     */
    invalidCredentials: function (shopId) {
        this.markCredentialFieldsAsInvalid(
            this.getPanel().getUsernameField(shopId),
            this.getPanel().getPasswordField(shopId)
        );
        Ext.Msg.alert(
            '{s name="dhl_scraper/modals/invalid_credentials/title"}{/s}',
            '{s name="dhl_scraper/modals/invalid_credentials/message"}{/s}'
        );
    },

    /**
     * @param { Ext.form.field.Text } usernameField
     * @param { Ext.form.field.Text } passwordField
     */
    markCredentialFieldsAsInvalid: function (usernameField, passwordField) {
        usernameField.markInvalid('{s name="dhl_scraper/form_errors/invalid_credentials/message"}{/s}');
        passwordField.markInvalid('{s name="dhl_scraper/form_errors/invalid_credentials/message"}{/s}');
    },

    /**
     * Map the EKP (customer number) to the config field.
     *
     * @param { Ext.form.field.Textfield } customerNumberField
     * @param { string } EKP
     */
    mapCustomerNumberToField: function (customerNumberField, EKP) {
        customerNumberField.setValue(EKP);
    },

    /**
     * Map all attendance numbers to the retrospective fields.
     *
     * @param { string } configName
     * @param { int } shopId
     */
    mapAttendanceNumbers: function (accountInformation, shopId) {
        var panel = this.getPanel();
        var mapAttendanceNumbers = function mapAttendanceNumbers(configName, productInformation) {
            var field = panel.getFormFieldOfSubShop(shopId, configName);
            this.mapAttendanceNumberToField(field, productInformation.attendanceNumbers);
        };

        Ext.Object.each(
            accountInformation,
            mapAttendanceNumbers.bind(this)
        );
    },

    /**
     * Map the attendance number to the retrospective field.
     *
     * @param { object } field
     * @param { array } attendanceNumbers
     */
    mapAttendanceNumberToField: function (field, attendanceNumbers) {
        if (!field) {
            return;
        }

        // By default always map the first value of the attendanceNumbers
        field.setValue(attendanceNumbers[0]);
    },

    /**
     * Iterates over all products and checks if some products have more attendance numbers.
     *
     * @param { Ext.form.Panel } accountInformation
     * @return { string }
     */
    getProductsThatHaveMoreAttendanceNumbers: function (accountInformation) {
        var mappedProductNameWithAttendanceNumbers = '';
        var getProducts = function (configName, productInformation) {
            if (this.hasMoreAttendanceNumbers(productInformation.attendanceNumbers)) {
                mappedProductNameWithAttendanceNumbers += this.concatProductNameWithAttendanceNumbers(
                    productInformation.productName,
                    productInformation.attendanceNumbers
                );
            }
        };

        Ext.Object.each(
            accountInformation,
            getProducts.bind(this)
        );

        return mappedProductNameWithAttendanceNumbers;
    },

    /**
     * Check if the array associated to a product has more attendance numbers.
     *
     * @param { array } attendanceNumbers
     * @return { boolean }
     */
    hasMoreAttendanceNumbers: function (attendanceNumbers) {
        return attendanceNumbers.length > 1;
    },

    /**
     * @param { string } productName
     * @param { array } attendanceNumbers
     * @return { string }
     */
    concatProductNameWithAttendanceNumbers: function (productName, attendanceNumbers) {
        return productName + ' : ' + attendanceNumbers.join() + '<br>';
    },

    /**
     * @param { string } productsHaveMoreAttendanceNumbers
     */
    showGrowlMessageForMoreAttendanceNumbersIfPossible: function (productsHaveMoreAttendanceNumbers) {
        if (!productsHaveMoreAttendanceNumbers) {
            return;
        }

        var message = '{s name="dhl_scraper/notification/more_attendance_numbers/message"}{/s}'
            + '<br> <br>'
            + productsHaveMoreAttendanceNumbers;

        Shopware.Notification.createGrowlMessage(
            '{s name="dhl_scraper/notification/more_attendance_numbers/title"}{/s}',
            message
        );
    },

    /**
     * Unpredictable server errors.
     *
     * @param { object } response
     * @param { object } eOpts
     */
    onDHLScraperServerFailure: function (response, eOpts) {
        Ext.Msg.hide();

        // Enable the event source.
        eOpts.eventSource.setDisabled(false);

        Ext.Msg.alert(
            '{s name="dhl_scraper/modals/server_error/title"}{/s}',
            '{s name="dhl_scraper/modals/server_error/message"}{/s}'
        );
    },

});
