// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Bulk actions for lists of participants.
 *
 * @module     core_user/local/participants/bulkactions
 * @copyright  2020 Andrew Nicols <andrew@nicols.co.uk>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

import * as Repository from 'core_user/repository';
import * as Str from 'core/str';
import ModalEvents from 'core/modal_events';
import SaveCancelModal from 'core/modal_save_cancel';
import Notification from 'core/notification';
import Templates from 'core/templates';
import {add as notifyUser} from 'core/toast';

/**
 * Show the add note popup
 *
 * @param {Number} courseid
 * @param {Number[]} users
 * @param {String[]} noteStateNames
 * @param {HTMLElement} stateHelpIcon
 * @return {Promise}
 */
export const showAddNote = (courseid, users, noteStateNames, stateHelpIcon) => {
    if (!users.length) {
        // No users were selected.
        return Promise.resolve();
    }

    const states = [];
    for (let key in noteStateNames) {
        switch (key) {
            case 'draft':
                states.push({value: 'personal', label: noteStateNames[key]});
                break;
            case 'public':
                states.push({value: 'course', label: noteStateNames[key], selected: 1});
                break;
            case 'site':
                states.push({value: key, label: noteStateNames[key]});
                break;
        }
    }

    const context = {
        stateNames: states,
        stateHelpIcon: stateHelpIcon.innerHTML,
    };

    let titlePromise = null;
    if (users.length === 1) {
        titlePromise = Str.get_string('addbulknotesingle', 'core_notes');
    } else {
        titlePromise = Str.get_string('addbulknote', 'core_notes', users.length);
    }

    return SaveCancelModal.create({
        body: Templates.render('core_user/add_bulk_note', context),
        title: titlePromise,
        buttons: {
            save: titlePromise,
        },
        removeOnClose: true,
        show: true,
    })
    .then(modal => {
        modal.getRoot().on(ModalEvents.save, () => submitAddNote(courseid, users, modal));
        return modal;
    });
};

/**
 * Add a note to this list of users.
 *
 * @param {Number} courseid
 * @param {Number[]} users
 * @param {Modal} modal
 * @return {Promise}
 */
const submitAddNote = (courseid, users, modal) => {
    const text = modal.getRoot().find('form textarea').val();
    const publishstate = modal.getRoot().find('form select').val();

    const notes = users.map(userid => {
        return {
            userid,
            text,
            courseid,
            publishstate,
        };
    });

    return Repository.createNotesForUsers(notes)
    .then(noteIds => {
        if (noteIds.length === 1) {
            return Str.get_string('addbulknotedonesingle', 'core_notes');
        } else {
            return Str.get_string('addbulknotedone', 'core_notes', noteIds.length);
        }
    })
    .then(msg => notifyUser(msg))
    .catch(Notification.exception);
};

/**
 * Show the send message popup.
 *
 * @param {Number[]} users
 * @return {Promise}
 */
export const showSendMessage = users => {
    if (!users.length) {
        // Nothing to do.
        return Promise.resolve();
    }

    let titlePromise;
    if (users.length === 1) {
        titlePromise = Str.get_string('sendbulkmessagesingle', 'core_message');
    } else {
        titlePromise = Str.get_string('sendbulkmessage', 'core_message', users.length);
    }

    return SaveCancelModal.create({
        body: Templates.render('core_user/send_bulk_message', {}),
        title: titlePromise,
        buttons: {
            save: titlePromise,
        },
        removeOnClose: true,
        show: true,
    })
    .then(modal => {
        modal.getRoot().on(ModalEvents.save, (e) => {
            const text = modal.getRoot().find('form textarea').val();
            if (text.trim() === '') {
                modal.getRoot().find('[data-role="messagetextrequired"]').removeAttr('hidden');
                e.preventDefault();
                return;
            }

            submitSendMessage(modal, users, text);
        });

        return modal;
    });
};

/**
 * Send a message to these users.
 *
 * @param {Modal} modal
 * @param {Number[]} users
 * @param {String} text
 * @return {Promise}
 */
const submitSendMessage = (modal, users, text) => {
    const messages = users.map(touserid => {
        return {
            touserid,
            text,
        };
    });
    return Repository.sendMessagesToUsers(messages)
    .then(messageIds => {
        // To help teachers know which users could not be sent to, let's build a notification.
        const cantSendToUsers = messageIds.filter(msg => msg.cantsendtouser && msg.cantsendtouser !== '');
        if (cantSendToUsers.length > 1) {
            // If there are multiple users who can't be sent to, extract their names and build an error message.
            const users = cantSendToUsers.map(user => user.cantsendtouser).join(', ');
            const stringPromise = Str.get_string('usercantbemessagedbulk', 'core_message', users);
            stringPromise.done(msg => {
                Notification.addNotification({
                    message: msg,
                    type: 'error',
                });
            });
        } else if (cantSendToUsers.length === 1) {
            // If there was only one error, just notify with the singular 'usercantbemessaged' string (already built in PHP).
            Notification.addNotification({
                message: cantSendToUsers[0].errormessage,
                type: 'error',
            });
        }
        // Always handle other errors independently.
        const otherErrors = messageIds.filter(msg => msg.errormessage && (!msg.cantsendtouser || msg.cantsendtouser === ''));
        otherErrors.forEach(error => {
            Notification.addNotification({
                message: error.errormessage,
                type: 'error',
            });
        });

        // Determine appropriate success/error toast message based on send results.
        let toastMessage = '';
        const errorMessages = messageIds.filter(msg => msg.errormessage);
        const successCount = messageIds.length - errorMessages.length;
        if (successCount == 1 && errorMessages.length == 0) {
            toastMessage = Str.get_string('sendbulkmessagesentsingle', 'core_message');
        } else if (successCount > 1 && errorMessages.length == 0) {
            toastMessage = Str.get_string('sendbulkmessagesent', 'core_message', messageIds.length);
        } else {
            toastMessage = Str.get_string(
                'sendbulkmessagesentwitherrors',
                'core_message',
                {
                    sent: successCount,
                    total: messageIds.length
                }
            );
        }
        return {
            message: toastMessage,
            errors: errorMessages.length,
        };
    })
    .then(({message, errors}) => {
        if (errors > 0) {
            // Customise the toast message to indicate there was an issue with sending.
            const config = {
                type: 'warning',
                closeButton: true,
                autohide: false,
            };
            notifyUser(message, config);
        } else {
            notifyUser(message);
        }
        return;
    })
    .catch(Notification.exception);
};
