/* jslint node: true */
'use strict';

//  ENiGMA½
const MenuModule                    = require('./menu_module.js').MenuModule;
const {
    getSortedAvailMessageConferences,
    getAvailableMessageAreasByConfTag,
    getSortedAvailMessageAreasByConfTag,
    hasMessageConfAndAreaRead,
    filterMessageListByReadACS,
}                                   = require('./message_area.js');
const Errors                        = require('./enig_error.js').Errors;
const Message                       = require('./message.js');

//  deps
const _                             = require('lodash');

exports.moduleInfo = {
    name    : 'Message Base Search',
    desc    : 'Module for quickly searching the message base',
    author  : 'NuSkooler',
};

const MciViewIds = {
    search : {
        searchTerms : 1,
        search      : 2,
        conf        : 3,
        area        : 4,
        to          : 5,
        from        : 6,
        advSearch   : 7,
    }
};

exports.getModule = class MessageBaseSearch extends MenuModule {
    constructor(options) {
        super(options);

        this.menuMethods = {
            search : (formData, extraArgs, cb) => {
                return this.searchNow(formData, cb);
            }
        };
    }

    mciReady(mciData, cb) {
        super.mciReady(mciData, err => {
            if(err) {
                return cb(err);
            }

            this.prepViewController('search', 0, mciData.menu, (err, vc) => {
                if(err) {
                    return cb(err);
                }

                const confView  = vc.getView(MciViewIds.search.conf);
                const areaView  = vc.getView(MciViewIds.search.area);

                if(!confView || !areaView) {
                    return cb(Errors.DoesNotExist('Missing one or more required views'));
                }

                const availConfs = [ { text : '-ALL-', data : '' } ].concat(
                    getSortedAvailMessageConferences(this.client).map(conf => Object.assign(conf, { text : conf.conf.name, data : conf.confTag } )) || []
                );

                let availAreas = [ { text : '-ALL-', data : '' } ]; //  note: will populate if conf changes from ALL

                confView.setItems(availConfs);
                areaView.setItems(availAreas);

                confView.setFocusItemIndex(0);
                areaView.setFocusItemIndex(0);

                confView.on('index update', idx => {
                    availAreas = [ { text : '-ALL-', data : '' } ].concat(
                        getSortedAvailMessageAreasByConfTag(availConfs[idx].confTag, { client : this.client }).map(
                            area => Object.assign(area, { text : area.area.name, data : area.areaTag } )
                        )
                    );
                    areaView.setItems(availAreas);
                    areaView.setFocusItemIndex(0);
                });

                vc.switchFocus(MciViewIds.search.searchTerms);
                return cb(null);
            });
        });
    }

    searchNow(formData, cb) {
        const isAdvanced    = formData.submitId === MciViewIds.search.advSearch;
        const value         = formData.value;

        const filter = {
            resultType      : 'messageList',
            sort            : 'modTimestamp',
            terms           : value.searchTerms,
            //extraFields       : [ 'area_tag', 'message_uuid', 'reply_to_message_id', 'to_user_name', 'from_user_name', 'subject', 'modified_timestamp' ],
            limit           : 2048, //  :TODO: best way to handle this? we should probably let the user know if some results are returned
        };

        const returnNoResults = () => {
            return this.gotoMenu(
                this.menuConfig.config.noResultsMenu || 'messageSearchNoResults',
                { menuFlags : [ 'popParent' ] },
                cb
            );
        };

        if(isAdvanced) {
            filter.toUserName   = value.toUserName;
            filter.fromUserName = value.fromUserName;

            if(value.confTag && !value.areaTag) {
                //  areaTag may be a string or array of strings
                //  getAvailableMessageAreasByConfTag() returns a obj - we only need tags
                filter.areaTag = _.map(
                    getAvailableMessageAreasByConfTag(value.confTag, { client : this.client } ),
                    (area, areaTag) => areaTag
                );
            } else if(value.areaTag) {
                if(hasMessageConfAndAreaRead(this.client, value.areaTag)) {
                    filter.areaTag = value.areaTag; //  specific conf + area
                } else {
                    return returnNoResults();
                }
            }
        }

        Message.findMessages(filter, (err, messageList) => {
            if(err) {
                return cb(err);
            }

            //  don't include results without ACS -- if the user searched by
            //  explicit conf/area tag, we should have already filtered (above)
            if(!value.confTag && !value.areaTag) {
                messageList = filterMessageListByReadACS(this.client, messageList);
            }

            if(0 === messageList.length) {
                return returnNoResults();
            }

            const menuOpts = {
                extraArgs : {
                    messageList,
                    noUpdateLastReadId  : true
                },
                menuFlags   : [ 'popParent' ],
            };

            return this.gotoMenu(
                this.menuConfig.config.messageListMenu || 'messageAreaMessageList',
                menuOpts,
                cb
            );
        });
    }
};