/** This file is part of Reactor.
 *  Copyright (c) 2020-2025 Kedron Holdings LLC, All Rights Reserved.
 *  Reactor is not public domain or open source. Distribution or derivative works are expressly prohibited.
 */

export const version = 25310;

import Reaction from '/client/Reaction.js';

import { showSysModal, asyncForEach } from './reactor-ui-common.js';

import { _T } from './i18n.js';

import ReactionEditor from "./reaction-editor.js";

import Tab from "./tab.js";
import ReactionList from "./reaction-list.js";

export default (function($) {

    const tabId = "tab-reactions";
    var tabInstance = false;

    class ReactionsTab extends Tab {
        constructor( $parent ) {
            super( tabId, $parent );

            this.editor = null;
            this.list = null;
        }

        async toggleDetail( event ) {
            const $row = $( event.currentTarget ).closest( 'div.re-reaction' );
            const id = $row.attr( 'id' );
            const $el = $( '#detail-' + id + '.collapse' );
            if ( ! $el.hasClass( 'loaded' ) ) {
                const reaction = await Reaction.getInstance( id );
                if ( reaction ) {
                    await reaction.refresh();
                    const $body = $( '.card-body', $el ).empty();
                    if ( 0 === (reaction.actions || []).length ) {
                        $body.text( _T('This reaction is empty.') );
                    } else {
                        const $list = $( '<ol></ol>' ).appendTo( $body );
                        await asyncForEach( reaction.actions || [], async ( action ) => {
                            try {
                                let str = await ReactionEditor.makeActionDescription( action );
                                $( '<li></li>' ).text( str ).appendTo( $list );
                            } catch( e ) {
                                console.log( e );
                                $( '<li></li>' ).text( "ERROR" ).appendTo( $list );
                            }
                        });
                    }
                    const $rr = $( '<div></div>' )
                        .text( _T('Reaction ID: {0}', "" ) )
                        .appendTo( $body );
                    $( '<span></span>' ).addClass( "user-select-all" )
                        .text( reaction.id )
                        .appendTo( $rr );
                    $el.addClass( 'loaded' );
                } else {
                    return;
                }
            }
            if ( $el.hasClass( 'show' ) ) {
                $el.slideUp( 250 ).removeClass( 'show' );
                $( '.re-reaction-name > i', $row ).removeClass( 'bi-chevron-down' ).addClass( 'bi-chevron-right' );
            } else {
                $el.slideDown( 250 ).addClass( 'show' );
                $( '.re-reaction-name > i', $row ).removeClass( 'bi-chevron-right' ).addClass( 'bi-chevron-down' );
            }
            return false;
        };

        async editReaction( reaction, isNew ) {
            const self = this;
            const $tab = this.getTabElement();
            $tab.empty();
            $tab.data( 'mode', 'edit' ).attr( 'data-mode', 'edit' );

            let newReaction = !!isNew;

            const $ct = $('<div class="container-fluid re-editor-controls"></div>' ).appendTo( $tab );
            const $row = $( '<div class="row"></div>' ).appendTo( $ct );
            $( '<div class="col"><h1></h1></div>' ).appendTo( $row );
            $( `<div class="col text-end mt-3">
      <button class="btn btn-sm btn-success saveconf">${_T(['#edit-button-save','Save'])}</button>
      <button class="btn btn-sm btn-danger revertconf">${_T(['#edit-button-exit','Exit'])}</button>
    </div>` ).appendTo( $row );
            $( 'btn', $row ).prop( 'disabled', true );
            $( 'h1', $row ).text( reaction.name || reaction.id ).on( 'click', function( ev ) {
                const $el = $( ev.currentTarget );
                const $form = $( '<div class="form-group"><input id="newname" class="form-control form-control-sm"></div>' );
                $( 'input', $form ).val( $el.text() );
                showSysModal({
                    title: _T(['#reaction-rename-title','Rename Reaction']),
                    body: $form,
                    buttons: [{
                        label: _T(['#reaction-rename-button-cancel','Cancel']),
                        class: "btn-primary",
                        close: true
                    },{
                        label: _T(['#reaction-rename-button-rename','Rename']),
                        class: "btn-success",
                        event: "rename"
                    }
                ]
                }).then( data => {
                    if ( "rename" === data ) {
                        const newname = $( '#sysdialog #newname' ).val() || "";
                        if ( "" !== newname && newname !== reaction.name ) {
                            self.editor.rename( newname );
                            $el.text( newname );
                        }
                    }
                });
            });
            $( 'button.saveconf', $ct ).on( 'click', async function( ev ) {
                const $el = $( ev.currentTarget );
                if ( ! self.editor.canSave() ) {
                    showSysModal( {
                        title: 'Uncorrected errors remain!',
                        body: 'Please correct the indicated errors before saving.'
                    } );
                    return;
                }
                $( 'button.saveconf', $tab ).prop( 'disabled', true );
                const reaction = self.editor.data;
                console.log("Saving", reaction.id);
                const robj = await Reaction.getInstance( reaction.id );
                const dobj = robj.getDataObject();
                reaction.serial = ( reaction.serial || 0 ) + 1;
                reaction.mdt = Date.now();
                dobj.setValue( reaction );
                dobj.save().then( function() {
                    self.editor.notifySaved();
                    newReaction = false;
                    if ( $el.hasClass( 'saveexit' ) ) {
                        self.closeEditor();
                    }
                }).catch( function( err ) {
                    console.log("save failed",err);
                    showSysModal( {
                        title: _T('#dialog-error-title'),
                        body: _T('The save failed; try again. {0}')
                    } );
                    self.editor.updateSaveControls();
                });
            });
            $( 'button.revertconf', $ct ).on( 'click', async function( /* ev */ ) {
                const reaction = self.editor.data;
                const robj = await Reaction.getInstance( reaction.id );
                if ( self.editor.isModified() ) {
                    showSysModal( {
                        title: _T(['#reactionedit-unsaved-title','Reaction Modified (Unsaved Changes)']),
                        body: _T(['#reactionedit-unsaved-prompt','You have unsaved changes to this reaction. Really discard changes and exit?']),
                        buttons: [{
                            label: _T(['#reactionedit-unsaved-button-discard','Discard Changes']),
                            event: "discard",
                            class: "btn-danger"
                        },{
                            label: _T(['#reactionedit-unsaved-button-cancel','Cancel']),
                            close: true,
                            class: "btn-success"
                        }]
                    }).then( async data => {
                        if ( "discard" === data ) {
                            self.closeEditor();  // close editor first for unsubscribe/disconnects
                            if ( newReaction ) {
                                await robj.delete();
                            }
                        }
                    });
                } else {
                    self.closeEditor();  // close editor first for unsubscribe/disconnects
                    if ( newReaction ) {
                        await robj.delete();
                    }
                }
            });

            this.editor = new ReactionEditor( reaction, $tab, { fixedName: reaction.name || reaction.id } );
            this.editor.editor().on( 'update-controls', function( ev, ui ) {
                /* During editing, various changes make the reaction saveable, or not. */
                console.log("got update-controls");
                $( 'button.saveconf', $tab ).prop( 'disabled', ui.errors || !ui.modified );
                $( 'button.revertconf', $tab ).prop( 'disabled', false );
            }).on( 'modified', function( ev, ui ) {
                /* Sent when the cached reaction is modified (no errors) */
                console.log("got modified");
                $( 'button.saveconf', $tab ).prop( 'disabled', ui.errors || !ui.modified );
                $( 'button.revertconf', $tab ).prop( 'disabled', false );
            });

            this.editor.edit();
            if ( newReaction ) {
                this.editor.signalModified();
            }
        }

        closeEditor() {
            const $tab = this.getTabElement();
            if ( this.editor ) {
                this.editor.close();
                this.editor = null;
            }
            $tab.empty();
            $tab.removeData( 'mode' ).attr( 'data-mode', null );
            this.getTabElement().trigger( 'activate' );
        }

        async activate( event ) {
            console.log("Reactions tab activated,", event);
            const $tab = this.getTabElement();

            /* If editing, don't paint this, it's just an event that bubbled up to us */
            if ( this.editor || "edit" === $tab.data( 'mode' ) ) {
                console.log("Stopping event in edit mode", this.editor);
                return false;
            }

            if ( ! this.list ) {
                this.list = new ReactionList( $tab, $tab );
            }

            const allReactions = await Reaction.getGlobalReactions();
            const reactions = allReactions.filter( r => ! r.ruleset );   // only those not belonging to a ruleset
            reactions.sort( function( a, b ) {
                return (a.name || a.id).localeCompare( b.name || b.id, undefined, { sensitivity: 'base' } );
            });

            this.list.show( reactions );

            $tab.data( 'mode', 'list' ).attr( 'data-mode', 'list' );
        };

        canSuspend() {
            return this.list ? this.list.canSuspend() : true;
        }

        suspending() {
            if ( this.list ) {
                this.list.suspending();
                this.list = null;
            }
            this.getTabElement().removeData( 'mode' ).attr( 'data-mode', null );
        };
    };

    return {
        "init": function( $main ) {
            if ( ! tabInstance ) {
                tabInstance = new ReactionsTab( $main );
            }
        },
        "tab": () => tabInstance.getTabElement()
    };
})(jQuery);
