/*
 *  Copyright 2024 Anyware Services
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

/**
 * This tool displays the thread of an Ametys object
 * @private
 */
Ext.define('Ametys.plugins.cms.threads.AmetysObjectThreadTool', {
    extend: "Ametys.tool.SelectionTool",
    
    statics: 
    {
        /**
         * Edit the thread
         * @property {String} threadId The thread id
         */
        editThread: function (threadId)
        {
            let tool = Ametys.tool.ToolsManager.getTool(Ametys.plugins.cms.threads.AmetysObjectThreadTool._toolId);
            
            tool.serverCall (
                'getComment', 
                [tool._objectId, threadId], 
                function(data)
                {
                    let textArea = tool._timeline.down("#comment-input");
                    textArea.setValue(data.content);
                    textArea.focus();
                    
                    let sendButton = tool._timeline.down("#comment-send-button");
                    sendButton.enable(); // Enable it before setting the tooltip
                    sendButton.setTooltip("{{i18n PLUGINS_CMS_UITOOL_AMETYS_OBJECT_THREAD_EDIT_COMMENT_BTN}}");
                    
                    tool._timeline.addCls("disabled-timeline");
                    tool._editedCommentId = threadId;
                    
                    let timelineItems = tool._timeline.getEl().select(".timeline-item").elements;
                    for (let item of timelineItems)
                    {
                        let extJsItem = Ext.get(item);
                        let table = extJsItem.up("table");
                        if (extJsItem.getAttribute("data-id") == threadId)
                        {
                            table.addCls("edited-timeline-item");
                        }
                        else
                        {
                            table.removeCls("edited-timeline-item");
                        }
                    }
                }, 
                { 
                    errorMessage: true, 
                    waitMessage: { target: tool.getWrapper() }
                }
            );
        },
        
        /**
         * Delete the thread
         * @property {String} threadId The thread id
         */
        deleteThread: function (threadId)
        {
            let tool = Ametys.tool.ToolsManager.getTool(Ametys.plugins.cms.threads.AmetysObjectThreadTool._toolId);

            Ametys.Msg.confirm(
                "{{i18n PLUGINS_CMS_UITOOL_AMETYS_OBJECT_THREAD_DELETE_TITLE}}", 
                "{{i18n PLUGINS_CMS_UITOOL_AMETYS_OBJECT_THREAD_DELETE_MSG}}", 
                function(btn) {
                    if (btn == 'yes')
                    {
                        this.serverCall (
                            'deleteComment', 
                            [this._objectId, threadId], 
                            function(data)
                            {
                                this.showOutOfDate();
                            }, 
                            { 
                                errorMessage: true, 
                                waitMessage: true
                            }
                        );
                    }
                }, 
                tool
            );
            
        }
    },

    /** @cfg {String} triggerChar=@ The char that starts mentions */
    triggerChar: '@',
    
    /**
     * @private
     * @property {Ametys.timeline.Timeline} _timeline the timeline of comments
     */
    
    /**
     * @private
     * @property {String} _objectId the id of the selected object
     */
    _objectId: null,
    
    /**
     * @private
     * @property {String} _editedCommentId the edited comment id
     */
    _editedCommentId: null,
    
    /**
     * @private
     * @property {Ext.Template} _contentHintTpl The template used for hint description
     */
    _contentHintTpl: new Ext.Template("{{i18n PLUGINS_CMS_UITOOL_AMETYS_OBJECT_THREAD_CONTENT_HINT}}"),
    
    /**
     * @private
     * @property {Ext.Template} _mentionedUserTpl The template used for mentiond users in comment content
     */
    _mentionedUserTpl: new Ext.Template("<span class='mention {cls}' data-qtip='{userTooltip}'>{triggerChar}{username}</span>"),
    
    /**
     * @private
     * A cache for user rights
     */
    _userRightsCache: {},
    
    constructor: function()
    {
        this.callParent(arguments);
        
        Ametys.plugins.cms.threads.AmetysObjectThreadTool._toolId = this.id;
        
        Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._onObjectDeleted, this);
    },
    
    createPanel: function()
    {
        var me = this;
        this._timeline = Ext.create('Ametys.timeline.Timeline', {
            scrollable: true,
            
            dockedItems: [{
                xtype: 'component',
                dock: 'top',
                ui: 'tool-hintmessage',
                itemId: 'object-info',
                html: ''
            },
            {
                xtype: 'toolbar',
                dock: 'top',
                layout: {
                    type: 'hbox',
                    align: 'stretch'
                },
                items: [
                    {
                        // Comment input
                        xtype: 'ametystextarea.withmentions',
                        cls: 'ametys',
                        flex: 1,
                        itemId: 'comment-input',
                        emptyText: "{{i18n PLUGINS_CMS_UITOOL_AMETYS_OBJECT_THREAD_INPUT_EMPTY}}",
                        msgTarget: 'qtip',
                        triggerChar: this.triggerChar,
                        renderMentionedUserFn: Ext.bind(this._renderMentionedUser, this),
                        listeners: {
                            change: this._onFieldChange,
                            focus: this._onFieldFocus,
                            focusleave: this._onFieldFocusleave,
                            scope: this
                        }
                    },
                    {
                        xtype: 'container',
                        layout: 'vbox',
                        items: [
                            {
                                // Help
                                xtype: 'component',
                                html: '',
                                cls: 'ametys-description',
                                flex: 1,
                                listeners: {
                                   afterrender: function(me)
                                   {
                                       // Register the new tip with an element's ID
                                       Ext.tip.QuickTipManager.register({
                                           target: me.getId(), // Target button's ID
                                           text  : "{{i18n PLUGINS_CMS_UITOOL_AMETYS_OBJECT_THREAD_INPUT_DESC}}" // Tip content  
                                       });
                                   },
                                   destroy: function(me)
                                   {
                                       Ext.tip.QuickTipManager.unregister(me.getId());
                                   }
                               }
                            },
                            {
                                // Add button
                                xtype: 'button',
                                itemId: 'comment-send-button',
                                handler: Ext.bind (this._sendComment, me),
                                iconCls: 'a-btn-glyph ametysicon-desktop-paper-plane-light size-16',
                                cls: 'a-btn-light',
                                disabled: true,
                                flex: 1,
                                margin: '0 0 0 0'
                            }
                        ]
                    }
                ]
            }
            ],
            
            timelineItemHTML: ['<div data-id="{id}" class="timeline-item {additionalCls}">',
                                   '<div class="profile-img-wrap">',
                                       '<img src="{profileImg}" alt="">',
                                       '<div>{hour}</div>',
                                   '</div>',
                                   '<div class="contents-wrap">',
                                       '<span class="vertical-line"></span>',
                                       '<div class="text">',
                                           '<div class="header">',
                                               '<strong class="title" data-qtip="{userTooltip}">{username}</strong></br>',
                                               '<div class="header-buttons">',
                                                   '<tpl if="canEdit">',
                                                      '<span data-qtip="{{i18n PLUGINS_CMS_UITOOL_AMETYS_OBJECT_THREAD_EDIT_TOOLTIP}}" onclick="Ametys.plugins.cms.threads.AmetysObjectThreadTool.editThread(\'{id}\')" class="thread-button a-btn-glyph ametysicon-edit45"></span>',
                                                   '</tpl>',
                                                   '<tpl if="canDelete">',
                                                        '<span data-qtip="{{i18n PLUGINS_CMS_UITOOL_AMETYS_OBJECT_THREAD_DELETE_TOOLTIP}}" onclick="Ametys.plugins.cms.threads.AmetysObjectThreadTool.deleteThread(\'{id}\')" class="thread-button a-btn-glyph ametysicon-sign-raw-cross"></span>',
                                                   '</tpl>',
                                               '</div>',
                                           '</div>',
                                           '<div class="content">',
                                           '{text}',
                                           '<tpl if="lastModified">',
                                               '<span class="thread-modified" data-qtip="{lastModified:date(Ext.Date.patterns.FriendlyDateTime)}">{{i18n PLUGINS_CMS_UITOOL_AMETYS_OBJECT_THREAD_EDIT_MSG}}</span>',
                                           '</tpl>',
                                           '</div>',
                                       '</div>',
                                   '</div>',
                               '</div>'],
        });
        
        return Ext.create('Ext.panel.Panel', {
            cls: 'ao-thread-tool',
            scrollable: false, 
            border: false,
            layout: 'card',
            activeItem: 0,
            
            items: [{
                    xtype: 'component',
                    cls: 'a-panel-text-empty',
                    border: false,
                    html: ''
                }, 
                this._timeline
            ]
        });
    },
    
    _renderMentionedUser: function(mention, displayField, prefixChar)
    {
        let highlightCls = "current-user";
        let isCurrentUser = this._isCurrentUser(mention.data);
        if (!isCurrentUser)
        {
            highlightCls = "";
            let userId = mention.id;
            if (this._userRightsCache[userId] == null)
            {
                this._checkRight(userId);
            }
            else if (!this._userRightsCache[userId])
            {
                highlightCls = "no-right";
            }
        }
        
        return "<strong data-display-user=\"" + mention.id + "\" + class=\"" + highlightCls + "\"><span>" + prefixChar + mention.get(displayField) + "</span></strong>";
    },
    
    _checkRight: function(userId)
    {
        let me = this;
        this.serverCall (
            'hasAccessRight', 
            [userId, this._objectId], 
            function(hasRight) 
            {
                if (!hasRight)
                {
                    Ext.select("[data-display-user=\"" + userId + "\"]").addCls("no-right");
                }
                me._userRightsCache[userId] = hasRight;
            }, 
            { 
                waitMessage: false, 
                errorMessage: false
            }
        );
    },
    
    refresh: function ()
    {
        this.showRefreshing();
        
        this._userRightsCache = {};
        
        var objectTarget = this.getCurrentSelectionTargets()[0];
        this._objectId = objectTarget.getParameters().id;
        
        this._timeline.getComponent("object-info").update(this._contentHintTpl.applyTemplate([Ext.String.escapeHtml(objectTarget.getParameters().title)]));
        
        var comment = this._timeline.queryById("comment-input");
        comment.reset();
        
        this._clearEdition();
        
        let sendButton = this._timeline.down("#comment-send-button");
        sendButton.setTooltip("{{i18n PLUGINS_CMS_UITOOL_AMETYS_OBJECT_THREAD_SEND_COMMENT_BTN}}");
        
        this.serverCall ('getThread', [this._objectId], this._getCommentsCb, { errorMessage: true });
    },
    
    /**
     * Clear the filter search
     * @param {Ext.Button} btn The button
     * @private
     */
    _sendComment: function()
    {
        var comment = this._timeline.queryById("comment-input");
        var commentValue = this._escapeCommentText(comment.getValue());

        if (this._editedCommentId)
        {
            this.serverCall ('editComment', [this._objectId, this._editedCommentId, commentValue], this._editCommentCb, { errorMessage: true, refreshing: true });
        }
        else
        {
            this.serverCall ('addComment', [this._objectId, commentValue], this._addCommentCb, { errorMessage: true, refreshing: true });
        }
        
    },
    
    _addCommentCb: function()
    {
        var comment = this._timeline.queryById("comment-input");
        comment.reset();
        
        this.showOutOfDate();
    },
    
    _editCommentCb: function()
    {
        this._clearEdition();
        
        var comment = this._timeline.queryById("comment-input");
        comment.reset();
        this.showOutOfDate();
    },
    
    _clearEdition: function()
    {
        this._editedCommentId = null;
        this._timeline.removeCls("disabled-timeline");
        
        let timelineItems = this._timeline.getEl().select(".timeline-item").elements;
        for (let item of timelineItems)
        {
            let extJsItem = Ext.get(item);
            let table = extJsItem.up("table");
            table.removeCls("edited-timeline-item");
        }
    },
    
    /**
     * @private
     * Callback function called after retrieving the 'alert' state of content targets
     * @param params The JSON result 
     */
    _getCommentsCb: function (comments)
    {
        var data = [];
        
        for (var i = 0; i < comments.length; i++)
        {
            var d = this._convertComment2Timeline(comments[i]);
            data.push(d);
        }
        
        this._timeline.getStore().loadData(data);
        this.getContentPanel().getLayout().setActiveItem(1);
        this.showRefreshed();
    },
    
    _convertComment2Timeline: function (comment)
    {
        var additionalCls;
        if (this._isCurrentUser(comment.author))
        {
            additionalCls = 'current-user';
        }
        
        var username = comment.author.fullname || "{{i18n plugin.core:PLUGINS_CORE_USERS_UNKNOWN_USER}}";
        var userTooltip = this._getUserTooltip(comment.author, false);
        
        var text = comment.mentions ? this._convertCommentContentMentions(comment) : comment.content;
        
        return {
            date: comment["creation-date"],
            additionalCls: additionalCls, 
            username: username,
            userTooltip: userTooltip,
            profileImg: Ametys.helper.Users.getUserImage(comment.author.login, comment.author.populationId, 46),
            text: text,
            canEdit: comment.canEdit,
            canDelete: comment.canDelete,
            lastModified: comment["modification-date"],
            id: comment.id
        }
    },
    
    _convertCommentContentMentions: function (comment)
    {
        var text = comment.content;
        
        for (var i = 0; i < comment.mentions.length; i++)
        {
            var mentionedUser = comment.mentions[i];
            
            var username = mentionedUser.fullname ? mentionedUser.fullname : "{{i18n plugin.core:PLUGINS_CORE_USERS_UNKNOWN_USER}}";
            var userTooltip = this._getUserTooltip(mentionedUser, true);
            var cls = this._getMentionedUserCls(mentionedUser);
            
            var replaceMentionBy = this._mentionedUserTpl.applyTemplate( {
                userTooltip: userTooltip,
                username: username,
                cls: cls,
                triggerChar: this.triggerChar
            });
            
            var login = mentionedUser.login;
            var populationId = mentionedUser.populationId;
            var mentionValue = "@(" + login + "#" + populationId + ")";
            
            text = text.replaceAll(mentionValue, replaceMentionBy);
        }
        
        return text;
    },
    
    _getMentionedUserCls: function(user)
    {
        if (this._isCurrentUser(user))
        {
            return 'current-user'
        }
        else if (!user.hasRight)
        {
            return 'no-right'
        }
        
        return null;
    },
    
    _isCurrentUser: function (user)
    {
        var currentUser = Ametys.getAppParameter('user');
        return currentUser.login === user.login && currentUser.population === user.populationId;
    },
    
    _getUserTooltip: function(user, checkRight)
    {
        var login = user.login;
        var populationId = user.populationId;
        var username = user.fullname || "{{i18n plugin.core:PLUGINS_CORE_USERS_UNKNOWN_USER}}";
        
        var populationLabel = user.populationLabel || populationId;
        var renderUser = Ametys.helper.Users.renderUser(login, populationLabel, username);
        
        return !checkRight || user.hasRight 
            ? renderUser
            : renderUser + "<br/><i>{{i18n plugin.cms:PLUGINS_CMS_UITOOL_AMETYS_OBJECT_THREAD_NO_RIGHT_TOOLTIP}}</strong></i>"
    },
    
    _onFieldChange: function(field, newValue)
    {
        var sendCommentButton = this._timeline.queryById("comment-send-button");
        var disable = Ext.isEmpty(newValue);
        sendCommentButton.setDisabled(disable);
    },
    
    _onFieldFocus: function(field)
    {
        field.addCls("a-field-focus");
    },
    
    _onFieldFocusleave: function(field)
    {
        field.removeCls("a-field-focus");
    },
    
    _escapeCommentText: function(text)
    {
        return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\n/g, '<br/>');
    },
    
    setNoSelectionMatchState: function (message)
    {
        this.callParent(arguments);
        
        var panel = this.getContentPanel().items.get(0);
        panel.update(message);
        this.getContentPanel().getLayout().setActiveItem(0);
        
        this._objectId = null;
    },

    _onObjectDeleted: function (message)
    {
        if (this.getTargetsInCurrentSelectionTargets(message).length > 0)
        {
            this.setNoSelectionMatchState();
        }
    }
});