( function($){
    "use strict";
    var prefix                    = 'gpls-wmfw-watermark-image-for-wordpress';
    var prefixUnderscored         = 'gpls_wmfw_watermark_image_for_wordpress';
    var localize_vars             = window[ prefixUnderscored + '_localize_vars' ];

    $(document).on( 'ready', (e) => {
        new Apply_Watermarks_Template();
    });

    class Apply_Watermarks_Template {

        constructor() {
            this.fetchedPosts                = [];
            this.savedPosts                  = {};
            this.fetchCPTPostsXHR            = null;
            this.cpts                        = [];
            this.posts                       = [];
            this.foundImagesPages            = 1;
            this.foundImages                 = {};
            this.selectedImagesDirect        = [];
            this.selectedImagesCPTs          = [];
            this.selectedImages              = [];
            this.applyWatermarksTemplateData = {};

            this.events();
            this.initSelect2();
        }

        events() {

            $('.main-loader').hide();
            $('.main-loader .fetching-data').addClass('d-none');
            $('[data-toggle="tooltip"]').tooltip();
            $('.' + localize_vars['classes_prefix'] + '-selected-images-direct-sortable').sortable();

            // Select Watermarks Template.
            $('#watermarks-template-selection').on( 'change', (e) => {
                var $this = $(e.target);
                var templateID = parseInt( $this.val() );
                if ( ! templateID ) {
                    $('.apply-watermarks-template-settings-wrapper .step-2').collapse('hide');
                    this.applyWatermarksTemplateData['templateID'] = 0;
                } else {
                    $('.apply-watermarks-template-settings-wrapper .step-2').collapse('show');
                    this.applyWatermarksTemplateData['templateID'] = templateID;
                }
            });

            // Select direct Images.
            $( '.apply-watermarks-template-selection-direct' ).on( 'click', (e) => {
                e.preventDefault();
                var mediaUploader;
                var $this = $(e.target);
                var context = $this.data('context');
                var options = {
                    title: localize_vars.labels.select_images,
                    library: {
                        orderby: 'date',
                        query: true,
                        post_mime_type: [ 'image/*' ],
                        [ prefix + '-context-modal' ]: 'create-watermark-template'
                    },
                    button: {
                        text: localize_vars.labels.select_images
                    },
                    multiple: true
                }

                mediaUploader = wp.media( options );
                mediaUploader.open();

                mediaUploader.on( 'select', (e) => {
                    var attachments = mediaUploader.state().get('selection').toJSON();
                    // console.log( 'selected attachments', attachments );
                    attachments.forEach( (attachment) => {
                        this.selectedImagesDirect.push( attachment['id'] );
                    });
                    this.selectedImages = this.selectedImagesDirect;
                    this.insertSelectedDirectImages( attachments );
                    $('.step-3').collapse('show');
                });
            });

            // Remove Direct Selected Image.
            $(document).on( 'click', '.' + localize_vars['classes_prefix'] + '-selected-images-direct .frame-remove', (e) => {
                var $this = $(e.target);
                if ( ! $this.hasClass('.frame-remove') ) {
                    $this = $this.parents('.frame-remove');
                }
                var attachmentID = $this.data('id');
                var imgIndex     = this.selectedImagesDirect.indexOf( parseInt( attachmentID ) );
                if ( imgIndex > -1 ) {
                    this.selectedImagesDirect.splice( imgIndex, 1 );
                    $this.parents('.img-item').remove();
                    this.selectedImages = this.selectedImagesDirect;
                    if ( ! this.selectedImages.length ) {
                        $('.step-3').collapse('hide');
                    }
                }
            });

            // On Toggle "Original" in Overwrite Select Option.
            $('#apply-watermarks-image-sizes-option-original').on( 'change', (e) => {
                var originalCheckBox = $(e.target)
                var applyTypeValue   = $('.apply-watermarks-template-type:checked').val();
                if ( 2 == applyTypeValue ) {
                    if ( originalCheckBox.is(':checked') ) {
                        $('.create-backup-option').collapse('show');
                    } else {
                        $('.create-backup-option').collapse('hide');
                    }
                }
            });

            // Toggle Apply Watermarks Template Overwrite Options.
            $(document).on( 'change', '.apply-watermarks-template-type', (e) => {
                var $this                                             = $(e.target);
                var value                                             = $this.val();
                var originalCheckBox                                  = $('#apply-watermarks-image-sizes-option-original');
                this.applyWatermarksTemplateData['applyTemplateType'] = value;
                if ( 2 == value ) {
                    if ( originalCheckBox.is(':checked') ) {
                        $('.create-backup-option').collapse('show');
                    }
                    $('.original-image-size-option').collapse('show');
                    $('.image-sizes-options-overwrite').collapse('show');
                    $('.image-sizes-options-new').collapse('hide');
                } else {
                    $('.create-backup-option').collapse('hide');
                    $('.original-image-size-option').collapse('hide');
                    $('.image-sizes-options-overwrite').collapse('hide');
                    $('.image-sizes-options-new').collapse('show');
                }
                $('.apply-watermarks-template-apply-subsizes-options').collapse('show');
            });

            // Toggle Select Images by options content accordion.
            $('.select-images-by-option').on( 'change', (e) => {
                var $this      = $(e.target);
                var selectType = $this.val();
                this.applyWatermarksTemplateData['selectImageType'] = selectType;
                $('#select-images-by-' + selectType ).collapse('show').siblings('.select-images-by-option-content').collapse('hide');

                if ( 'cpt' === selectType ) {
                    this.selectedImages = this.selectedImagesCPTs;
                } else if ( 'direct' === selectType ) {
                    this.selectedImages = this.selectedImagesDirect;
                }
                if ( ! this.selectedImages.length ) {
                    $('.step-3').collapse('hide');
                } else {
                    $('.step-3').collapse('show');
                    if ( this.applyWatermarksTemplateData.imageSizes && this.applyWatermarksTemplateData['imageSizes'].length ) {
                        $('.step-4').collapse('show');
                    }
                }
            });

            // Toggle Backup Button.
            $('.apply-watermarks-create-backup-option').on( 'change', (e) => {
                var $this = $(e.target);
                var value = $this.is(':checked');
                this.applyWatermarksTemplateData['createBackup'] = value;
            });

            // Toggle All Image Sizes Checkboxes.
            $('.apply-watermarks-image-sizes-options-all').on( 'change', (e) => {
                var $this = $(e.target);
                var value = $this.is(':checked');
                $('.apply-watermarks-image-sizes-option').prop( 'checked', value ).trigger('change');
            });

            // Choose Image sizes to apply Watermarks Template.
            $('.apply-watermarks-image-sizes-option').on( 'change', (e) => {
                var imageSizes   = [];
                var sizesOptions = $( '.apply-watermarks-image-sizes-option' );
                $.each( sizesOptions, (index, element) => {
                    var $this = $(element);
                    var value = $this.val();
                    if ( $this.is(':checked') ) {
                        imageSizes.push( value );
                    }
                });
                this.applyWatermarksTemplateData['imageSizes'] = imageSizes;
                if ( ! imageSizes.length ) {
                    $('.step-4').collapse('hide');
                } else {
                    $('.step-4').collapse('show');
                }
            });

            // Toggle the author required attribute based on checkbox.
            $('input[name="user_mapping_type"]').on( 'change', (e) => {
                if ( $('#user-mapping-single-author').prop('checked') ) {
                    if ( $('#user-mapping-single-author-select').val() ) {
                        $('.last-step-submit').prop('disabled', false );
                    } else {
                        $('.last-step-submit').prop('disabled', true );
                    }
                } else {
                    $('.last-step-submit').prop('disabled', false );
                }
            });

            $('#user-mapping-single-author-select').on( 'change', (e) => {
                var $this = $(e.target);
                if ( $this.val() ) {
                    $('.last-step-submit').prop('disabled', false );
                } else {
                    $('.last-step-submit').prop('disabled', true );
                }
            });

            // Toggle Select All functionality
            $('.taxonomy-select-all-checkbox').on( 'click', (e) => {
                var $this            = $(e.target);
                var checkSelectInput = $this.parent('label').prev('select');
                if ( $this.prop('checked') == true ) {
                    checkSelectInput.find('option').prop('selected', true );
                } else {
                    checkSelectInput.find('option').prop('selected', false );
                }
            });

            $(document).on( 'change', '.cpt-terms-select, .cpt-authors-select, .cpt-start-date-select, .cpt-end-date-select, .cpt-statuses-select', (e) => {
                this.foundImages = {};
            });

            //*********************** Specific Posts  *********************************//
            $('.select-list-all-tab').on( 'click', (e) => {
                var $this = $(e.target);
                var cpt   = $this.data('cpt');
                var paged = 1;
                if ( ! this.fetchedPosts[ cpt ] || ! this.fetchedPosts[ cpt ][ paged ] ) {
                    this.fetchCPTPost( cpt, paged );
                }

            });

            // Handle Pagination //

                // Next Page.
            $('.all-cpt-posts-pagination .next-page').on( 'click', (e) => {
                var $this = $(e.target);
                if ( ! $this.hasClass('button') ) {
                    $this = $this.parent();
                }
                var cpt               = $this.data('cpt');
                var paginationWrapper = $('#all-posts-pagination-' + cpt );
                var modal             = $this.closest('.gpls-all-posts-list-wrapper');
                var allPages          = parseInt( paginationWrapper.find('.total-pages').data('pages') );
                var currentPage       = parseInt( paginationWrapper.find('.current-page').text() );
                var nextPage          = currentPage + 1;

                // Update the current page val.
                paginationWrapper.find('.current-page').text( nextPage );
                modal.find('.cb-select-all-1').prop( 'checked', false );

                // get fetched posts from local var if exists otherwise, Fetch paged posts.
                if ( this.fetchedPosts[ cpt ] && this.fetchedPosts[ cpt ][ nextPage ] ) {
                    this.updateListPostsTable( cpt, this.fetchedPosts[ cpt ][ nextPage ], true );
                } else {
                    // Show the Loader.
                    this.toggleLoader( cpt, 'show' );

                    this.fetchCPTPost( cpt, nextPage );
                }

                // disable the next-last page buttons if reached end.
                if ( nextPage >= allPages ) {
                    paginationWrapper.find('.next-page').addClass( 'disabled' );
                    paginationWrapper.find('.last-page').addClass( 'disabled' );
                }

                paginationWrapper.find('.prev-page').removeClass( 'disabled' );
                paginationWrapper.find('.first-page').removeClass( 'disabled' );
            });

            // Last Page.
            $('.all-cpt-posts-pagination .last-page').on( 'click', (e) => {
                var $this = $(e.target);
                if ( ! $this.hasClass('button') ) {
                    $this = $this.parent();
                }
                var cpt               = $this.data('cpt');
                var paginationWrapper = $('#all-posts-pagination-' + cpt );
                var modal             = $this.closest('.gpls-all-posts-list-wrapper');
                var allPages          = parseInt( paginationWrapper.find('.total-pages').data('pages') );
                var currentPage       = parseInt( paginationWrapper.find('.current-page').text() );
                var lastPage          = parseInt( $this.data('paged') );

                // Update the current page val.
                paginationWrapper.find('.current-page').text( lastPage );
                modal.find('.cb-select-all-1').prop( 'checked', false );

                // get fetched posts from local var if exists otherwise, Fetch paged posts.
                if ( this.fetchedPosts[ cpt ] && this.fetchedPosts[ cpt ][ lastPage ] ) {
                    this.updateListPostsTable( cpt, this.fetchedPosts[ cpt ][ lastPage ], true );
                } else {
                    // Show the Loader.
                    this.toggleLoader( cpt, 'show' );

                    this.fetchCPTPost( cpt, lastPage );
                }

                // disable the next-last page buttons if reached end.
                paginationWrapper.find('.next-page').addClass( 'disabled' );
                paginationWrapper.find('.last-page').addClass( 'disabled' );


                paginationWrapper.find('.prev-page').removeClass( 'disabled' );
                paginationWrapper.find('.first-page').removeClass( 'disabled' );
            });

            // first Page.
            $('.all-cpt-posts-pagination .first-page').on( 'click', (e) => {
                var $this = $(e.target);
                if ( ! $this.hasClass('button') ) {
                    $this = $this.parent();
                }
                var cpt               = $this.data('cpt');
                var paginationWrapper = $('#all-posts-pagination-' + cpt );
                var modal             = $this.closest('.gpls-all-posts-list-wrapper');
                var allPages          = parseInt( paginationWrapper.find('.total-pages').data('pages') );
                var currentPage       = parseInt( paginationWrapper.find('.current-page').text() );
                var firstPage         = 1;

                // Update the current page val.
                paginationWrapper.find('.current-page').text( firstPage );
                modal.find('.cb-select-all-1').prop( 'checked', false );

                // get fetched posts from local var if exists otherwise, Fetch paged posts.
                if ( this.fetchedPosts[ cpt ] && this.fetchedPosts[ cpt ][ firstPage ] ) {
                    this.updateListPostsTable( cpt, this.fetchedPosts[ cpt ][ firstPage ], true );
                } else {
                    // Show the Loader.
                    this.toggleLoader( cpt, 'show' );

                    this.fetchCPTPost( cpt, firstPage );
                }

                // disable the next-last page buttons if reached end.
                paginationWrapper.find('.next-page').removeClass( 'disabled' );
                paginationWrapper.find('.last-page').removeClass( 'disabled' );

                paginationWrapper.find('.prev-page').addClass( 'disabled' );
                paginationWrapper.find('.first-page').addClass( 'disabled' );
            });

            // Prev Page.
            $('.all-cpt-posts-pagination .prev-page').on( 'click', (e) => {
                var $this = $(e.target);
                if ( ! $this.hasClass('button') ) {
                    $this = $this.parent();
                }
                var cpt               = $this.data('cpt');
                var modal             = $this.closest('.gpls-all-posts-list-wrapper');
                var paginationWrapper = $('#all-posts-pagination-' + cpt );
                var allPages          = parseInt( paginationWrapper.find('.total-pages').data('pages') );
                var currentPage       = parseInt( paginationWrapper.find('.current-page').text() );
                var prevPage          = currentPage - 1;

                // Update the current page val.
                paginationWrapper.find('.current-page').text( prevPage );
                modal.find('.cb-select-all-1').prop( 'checked', false );

                // get fetched posts from local var if exists otherwise, Fetch paged posts.
                if ( this.fetchedPosts[ cpt ] && this.fetchedPosts[ cpt ][ prevPage ] ) {
                    this.updateListPostsTable( cpt, this.fetchedPosts[ cpt ][ prevPage ], true );
                } else {
                    // Show the Loader.
                    this.toggleLoader( cpt, 'show' );

                    this.fetchCPTPost( cpt, prevPage );
                }

                // disable the next-last page buttons if reached end.
                if ( prevPage <= 1 ) {
                    paginationWrapper.find('.prev-page').addClass( 'disabled' );
                    paginationWrapper.find('.first-page').addClass( 'disabled' );
                }

                paginationWrapper.find('.next-page').removeClass( 'disabled' );
                paginationWrapper.find('.last-page').removeClass( 'disabled' );

            });

            // Page Number Box //
            $('.current-page').on( 'keypress', ( e ) => {
                var keycode = ( event.keyCode ? event.keyCode : event.which );
                var $this             = $(e.target);
                var cpt               = $this.data('cpt');
                var paginationWrapper = $('#all-posts-pagination-' + cpt );
                var allPages          = parseInt( paginationWrapper.find('.total-pages').data('pages') );
                var currentPage       = parseInt( paginationWrapper.find('.current-page').val() );

                if( keycode == '13' ) {
                    e.preventDefault();
                    if ( currentPage > 0 ) {
                        if ( this.fetchedPosts[ cpt ] && this.fetchedPosts[ cpt ][ currentPage ] ) {
                            this.updateListPostsTable( cpt, this.fetchedPosts[ cpt ][ currentPage ], true );
                        } else {
                            // Show the Loader.
                            this.toggleLoader( cpt, 'show' );
                            this.fetchCPTPost( cpt, currentPage );
                        }

                        paginationWrapper.find('.next-page').removeClass( 'disabled' );
                        paginationWrapper.find('.last-page').removeClass( 'disabled' );
                        paginationWrapper.find('.prev-page').removeClass( 'disabled' );
                        paginationWrapper.find('.first-page').removeClass( 'disabled' );

                        // disable the next-last page buttons if reached end.
                        if ( currentPage <= 1 ) {
                            paginationWrapper.find('.prev-page').addClass( 'disabled' );
                            paginationWrapper.find('.first-page').addClass( 'disabled' );
                        } else if ( currentPage > allPages ) {
                            paginationWrapper.find('.next-page').removeClass( 'disabled' );
                            paginationWrapper.find('.last-page').removeClass( 'disabled' );
                        }
                    } else {
                        if ( currentPage > allPages ) {
                            paginationWrapper.find('.current-page').val( allPages );
                        } else if ( currentPage < 1 ) {
                            paginationWrapper.find('.current-page').val( 1 );
                        }
                    }
                }

            });

            /********/

            // Toggle Collapse of selected CPT checkbox.
            $(document).on( 'change', '.cpt-name-checkbox', (e) => {
                var $this     = $(e.target);
                var cptSlug   = $this.val();
                var isChecked = $this.is(':checked');
                var selectFilterWrapper = $('.select-images-by-post-type-' + cptSlug + '-wrapper');
                if ( selectFilterWrapper.length ) {
                    selectFilterWrapper.collapse( isChecked ? 'show' : 'hide' );
                }
                this.foundImages = {};
            });

            // Toggle Select Other Option.
            $(document).on( 'change', '.cpt-select-type-radio', (e) => {
                var $this         = $(e.target);
                var parentWrapper = $this.closest('.subtitle');
                var otherFilter   = parentWrapper.find('.cpt-select-type-radio').not( $this );
               $( otherFilter.data('bs-target') ).collapse('hide');
            });

            $(document).on('change', '.cb-select-all-1', (e) => {
                var $this     = $(e.target);
                var table     = $this.parents('.wp-list-table');
                var isChecked = $this.is(':checked');
                $.each( table.find('.cb-select-all'), (index, element) => {
                    $(element).prop('checked', isChecked ).trigger('change');
                });
            });

            $(document).on('change', '.gpls-all-posts-list-wrapper .cb-select-all', (e) => {
                var $this = $(e.target);
                this.selectCheckedPost( $this );
                this.foundImages = {};
            });

            $(document).on('change', '#modal-found-images-watermarks-template .cb-select-all', (e) => {
                var $this = $(e.target);
                this.updateSelectedImages( $this );
            });


            // Remove Selected Post when clicking on Delete Button.
            $(document).on( 'click', '.remove-selected-post', (e) => {
                var $this = $(e.target);
                var postID = parseInt( $this.data('id') );
                var cpt    = $this.data('cpt');
                // remove the ID from the this.savedPosts Array.
                var postIDIndex = this.savedPosts[ cpt ].indexOf( postID );
                if  ( postIDIndex > -1 ) {
                    this.savedPosts[ cpt ].splice( postIDIndex, 1 );
                }
                // Update isChecked status in fetchedPosts list.
                this.updateFetchedPostCheckedStatus( cpt ,postID, false );
                // uncheck the checkbox if its on the same current page.
                var currentRowCheckBox = $('#cb-select-all-' + cpt + '-' + postID );
                if ( currentRowCheckBox.length ) {
                    currentRowCheckBox.prop( 'checked', false );
                }
                // remove the post row from the Selected Posts Tab content.
                $this.parents('.selected-posts-list-row').remove();
            });

            // On closing the specific posts modal.
            $('.specific-posts-modal').on( 'hidden.bs.modal', (e) => {
                var cpt                   = $(e.target).data('cpt');
                var cptSpecificPostsInput = $('.cpt_select_specific_posts_' + cpt );

                if ( this.savedPosts[ cpt ] ) {
                    cptSpecificPostsInput.val( this.savedPosts[ cpt ].join( ',' ) );
                } else {
                    cptSpecificPostsInput.val( '' );
                }
            });

            // Fire All Posts Section on show.
            $('.specific-posts-modal').on( 'shown.bs.modal', (e) => {
                var modalTarget = $(e.currentTarget);
                modalTarget.find('.select-list-all-tab').trigger('click');
            });


            // Search For images in selected Posts.
            $('.search-for-images-in-posts').on( 'click', (e) => {
                e.preventDefault();
                $('.selected-images-watermarks-template-modal').modal('show');
                if ( this.foundImages[1] ) {
                    var paginationWrapper = $('.selected-images-watermarks-template-modal .actions' );
                    this.updateListFoundImages( this.foundImages[1], paginationWrapper, 1, this.foundImagesPages, true );
                } else {
                    this.findImagesByPosts();
                }
            });

            $('.selected-images-watermarks-template-modal .next-page').on( 'click', (e) => {
                var $this = $(e.target);
                if ( ! $this.hasClass('button') ) {
                    $this = $this.parent();
                }
                var paginationWrapper = $('.selected-images-watermarks-template-modal .actions' );
                var allPages          = parseInt( paginationWrapper.find('.total-pages').data('pages') );
                var currentPage       = parseInt( paginationWrapper.find('.current-page').text() );
                var nextPage          = currentPage + 1;

                // Fill the Table.
                if ( this.foundImages[ nextPage ] ) {
                    this.updateListFoundImages( this.foundImages[ nextPage ], paginationWrapper, nextPage, allPages, true );
                } else {
                    this.findImagesByPosts( nextPage );
                }
            });

            $('.selected-images-watermarks-template-modal .prev-page').on( 'click', (e) => {
                var $this = $(e.target);
                if ( ! $this.hasClass('button') ) {
                    $this = $this.parent();
                }
                var paginationWrapper = $('.selected-images-watermarks-template-modal .all-found-images-pagination' );
                var allPages          = parseInt( paginationWrapper.find('.total-pages').data('pages') );
                var currentPage       = parseInt( paginationWrapper.find('.current-page').text() );
                var prevPage          = currentPage - 1;

                // Update the current page val.
                paginationWrapper.find('.current-page').val( prevPage );
                if ( this.foundImages[ prevPage ] ) {
                    this.updateListFoundImages( this.foundImages[ prevPage ], paginationWrapper, prevPage, allPages, true );
                } else {
                    this.findImagesByPosts( prevPage );
                }
            });

            $('.selected-images-watermarks-template-modal .first-page').on( 'click', (e) => {
                var $this = $(e.target);
                if ( ! $this.hasClass('button') ) {
                    $this = $this.parent();
                }
                var paginationWrapper = $('.selected-images-watermarks-template-modal .all-found-images-pagination' );
                var allPages          = parseInt( paginationWrapper.find('.total-pages').data('pages') );
                var firstPage         = 1;

                // Update the current page val.
                paginationWrapper.find('.current-page').val( firstPage );
                if ( this.foundImages[ firstPage ] ) {
                    this.updateListFoundImages( this.foundImages[ firstPage ], paginationWrapper, 1, allPages, true );
                } else {
                    this.findImagesByPosts( firstPage );
                }
            });

            $('.selected-images-watermarks-template-modal .last-page').on( 'click', (e) => {
                var $this = $(e.target);
                if ( ! $this.hasClass('button') ) {
                    $this = $this.parent();
                }
                var paginationWrapper = $('.selected-images-watermarks-template-modal .all-found-images-pagination' );
                var allPages          = parseInt( paginationWrapper.find('.total-pages').data('pages') );
                var lastPage          = parseInt( $this.data('paged') )

                // Update the current page val.
                paginationWrapper.find('.current-page').val( lastPage );
                if ( this.foundImages[ lastPage ] ) {
                    this.updateListFoundImages( this.foundImages[ lastPage ], paginationWrapper, lastPage, allPages, true );
                } else {
                    this.findImagesByPosts( lastPage );
                }
            });


            $(document).on( 'click', '.apply-watermarks-template-submit-btn', (e) => {
                e.preventDefault();
                this.applyWatermarksTemplate();
            });

            $(document).on( 'click', '.wp-list-select-posts-table .toggle-row', function() {
                $( this ).closest( 'tr' ).toggleClass( 'is-expanded' );
            });

            $(document).on( 'click', '.close-modal-btn', (e) => {
                e.preventDefault();
                var $this = $(e.target);
                var modal = $this.closest('.bulk-apply-modal');
                modal.modal('hide');
            });
        }

        initSelect2() {
            // Set terms select2.
            var termsSelects = $('.cpt-terms-select');
            termsSelects.each( function(index) {
                var id       = $(this).attr('id');
                var cpt      = $(this).data('cpt_type');
                var taxonomy = $(this).data('tax_name');
                taxonomyTermsSelect2( id, cpt, taxonomy );
            });
        }

        insertSelectedDirectImages( attachments ) {
            // console.log( 'attachments: ', attachments );
            var sortableWrapper = $('.' + localize_vars['classes_prefix'] + '-selected-images-direct');
            attachments.forEach( (attachment) => {
                var imgItem  = sortableWrapper.find('.img-item-clone').clone().removeClass('img-item-clone d-none').addClass('img-item');
                var editLink = attachment.editLink;
                editLink     = new URL( editLink );
                editLink.searchParams.set( localize_vars['classes_prefix'] + '-force-img-refresh', ( Math.random() + 1 ).toString(36).substring(7) );
                imgItem.find('.frame-remove').attr('data-id', attachment['id'] );
                imgItem.find('a').attr('href', editLink.href );
                imgItem.find('img').attr('src', ( attachment.sizes.thumbnail ? attachment.sizes.thumbnail.url : attachment.url ) );
                sortableWrapper.append( imgItem );
            });
        }

        setupPagination( paginationWrapperElement, currentPage, pagesCount ) {
            // First Page.
            paginationWrapperElement.find('.first-page').data( 'paged', 1 );
            // Current Page.
            paginationWrapperElement.find('.current-page').text( currentPage );
            // Total Pages.
            paginationWrapperElement.find('.total-pages').data('pages', pagesCount ).text( pagesCount );
            // Next Page.
            paginationWrapperElement.find('.next-page').data( 'paged', ( currentPage + 1 ) );
            // Last Page.
            paginationWrapperElement.find('.last-page').data( 'paged', pagesCount );

            paginationWrapperElement.find('.next-page').removeClass( 'disabled' );
            paginationWrapperElement.find('.last-page').removeClass( 'disabled' );
            paginationWrapperElement.find('.prev-page').removeClass( 'disabled' );
            paginationWrapperElement.find('.first-page').removeClass( 'disabled' );

            // Prev to first.
            if ( currentPage <= 1 ) {
                paginationWrapperElement.find('.prev-page').addClass( 'disabled' );
                paginationWrapperElement.find('.first-page').addClass( 'disabled' );
                if ( pagesCount <= 1 ) {
                    paginationWrapperElement.find('.next-page').addClass( 'disabled' );
                    paginationWrapperElement.find('.last-page').addClass( 'disabled' );
                }
            }
            // next to last.
            if ( currentPage >= pagesCount ) {
                paginationWrapperElement.find('.next-page').addClass( 'disabled' );
                paginationWrapperElement.find('.last-page').addClass( 'disabled' );
                if ( pagesCount <= 1 ) {
                    paginationWrapperElement.find('.prev-page').addClass( 'disabled' );
                    paginationWrapperElement.find('.first-page').addClass( 'disabled' );
                }
            }
        }

        calculatePosition( watermarkInfoObj ) {
            var width  = watermarkInfoObj['width'];
            var height = watermarkInfoObj['height'];
        }

        selectCheckedPost( $this ) {
            var cpt            = $this.data('cpt');
            var postRow        = $this.parents('.all-posts-list-row');
            var postID         = parseInt( $this.data('id') );
            var postTitle      = postRow.find('.column-title strong').text();
            var postDate       = postRow.find('.column-date strong').text();
            var postData       = {
                id: postID,
                title: postTitle,
                date: postDate
            };

            this.updateFetchedPostCheckedStatus( cpt, postID, true );

            if ( $this.is(':checked' ) ) {
                // Add the post ID to the this.savedPosts variable if not exists.
                if ( ! this.savedPosts[ cpt ] ) {
                    this.savedPosts[ cpt ] = [];
                }

                if  ( ! this.savedPosts[ cpt ].includes( postID ) ) {
                    this.savedPosts[ cpt ].push( postID );
                    // insert the selected post to the selectedPosts Section.
                    this.insertSelectedPost( cpt, postData );
                }
            } else {
                // remove the ID from the this.savedPosts Array.
                var postIDIndex = this.savedPosts[ cpt ].indexOf( postID );
                if  ( postIDIndex > -1 ) {
                    this.savedPosts[ cpt ].splice( postIDIndex, 1 );
                    if ( ! Object.keys( this.savedPosts[ cpt ] ).length ) {
                        delete this.savedPosts[ cpt ];
                    }
                }
                // remove the post row from the Selected Posts Tab content.
                $('#post-selected-' + postID ).remove();
            }
            // console.log( 'select checked post: ', this.savedPosts );
        }

        updateFetchedPostCheckedStatus( cpt, postID, checkStatus ) {
            for ( let paged in this.fetchedPosts[ cpt ] ) {
                for ( let fetchedPostID in this.fetchedPosts[ cpt ][ paged ] ) {
                    if ( fetchedPostID == postID ) {
                        this.fetchedPosts[ cpt ][ paged ][ postID ].isChecked = checkStatus;
                    }
                }
            }
        }

        updateSelectedImages( $this ) {
            var imageID = parseInt( $this.data('id') );
            if ( $this.is(':checked' ) ) {
                if ( ! this.selectedImagesCPTs.includes( imageID ) ) {
                    this.selectedImagesCPTs.push( imageID );
                    this.selectedImages = this.selectedImagesCPTs;
                }
            } else {
                var imageIDIndex = this.selectedImagesCPTs.indexOf( imageID );
                if  ( imageIDIndex > -1 ) {
                    this.selectedImagesCPTs.splice( imageIDIndex, 1 );
                    this.selectedImages = this.selectedImagesCPTs;
                }
            }

            if ( ! this.selectedImages.length ) {
                $('.step-3').collapse('hide');
            } else {
                $('.step-3').collapse('show');
                if ( this.applyWatermarksTemplateData.imageSizes && this.applyWatermarksTemplateData['imageSizes'].length ) {
                    $('.step-4').collapse('show');
                }
            }
        }

        updateListFoundImages( images, actionsRow, currentPage, totalPages, checkSelected = false ) {
            var wrapper     = $( '.selected-images-watermarks-template-modal' );
            var wrapperBody = wrapper.find('.wp-list-table').find('tbody');

            wrapperBody.html( images );

            if ( checkSelected ) {
                $.each( wrapper.find('.cb-select-all'), (index, element) => {
                    var $this   = $(element);
                    var imageID = parseInt( $this.data('id') );
                    if ( this.selectedImages.includes( imageID ) ) {
                        $this.prop('checked', true);
                    } else {
                        $this.prop('checked', false);
                    }
                });
            }
            if ( images.length ) {
                $('.step-3').collapse('show');
            } else {
                $('.step-3').collapse('hide');
            }
            this.setupPagination( actionsRow, currentPage, totalPages );
        }

        insertSelectedPost( cpt, postData ) {
            var selectedPostsTable  = $('#selected-posts-' + cpt + ' table tbody' );
            var selectedPostElement = `<tr class="iedit selected-posts-list-row" id="post-selected-` + postData['id'] + `" >
                    <td class="title column-title column-primary page-title" data-colname="Title">
                        <strong>` + postData['title'] + `</strong>
                        <button type="button" class="toggle-row"></button>
                    </td>
                    <td class="date column-date page-date" data-colname="Date">
                        <strong>` + postData['date'] + `</strong>
                    </td>
                    <td class="actions column-actions page-actions" data-colname="Actions">
                        <button data-id="` + postData['id'] + `" type="button" class="remove-selected-post btn btn-danger" data-cpt="` + cpt + `">Remove</button>
                    </td>
                </tr>`;
            selectedPostsTable.append( selectedPostElement );
        }

        fetchCPTPost( cpt, paged ) {
            var allPostsWrapper = $('#all-posts-' + cpt );
            this.toggleLoader( cpt, 'show' );

            if ( this.fetchCPTPostsXHR != null ) {
                this.fetchCPTPostsXHR.abort();
            }

            this.fetchCPTPostsXHR = $.ajax({
                method: 'POST',
                url: localize_vars.ajaxUrl,
                data: {
                    action: localize_vars.selectCptListAction,
                    nonce: localize_vars.nonce,
                    cpt: cpt,
                    paged: paged

                },
                success: ( resp ) => {
                    if ( resp['success'] && true == resp['success'] ) {
                        // Store the results in local variable.
                        if ( ! this.fetchedPosts[ cpt ] ) {
                            this.fetchedPosts[ cpt ] = {};
                        }
                        this.fetchedPosts[ cpt ][ paged ] = resp['data'];

                        // Update the table with the results.
                        this.updateListPostsTable( cpt, resp['data'] );
                    }
                },
                error: ( err ) => {
                    if ( err.status == 403 ) {
                        location.reload();
                    }
                },
                complete: () => {
                    this.toggleLoader( cpt, 'hide' );
                }
            });
        }

        findImagesByPosts( paged = 1 ) {
            var postTypes           = [];
            var selectType          = {};
            var selectSpecificPosts = {};
            var cptTerms            = {};
            var cptStatuses         = {};
            var cptAuthors          = {};
            var cptStartDate        = {};
            var cptEndDate          = {};

            $('.cpt-name-checkbox:checked').each( (index, element) =>  {
                postTypes.push( $(element).val() );
            });

            $('.cpt-select-type-radio:checked').each( (index, element) =>  {
                var key   = $(element).data('cpt_type');
                var value = $(element).val();
                selectType[ key ] = value;
            });

            $('.cpt_select_specific_posts').each( (index, element) =>  {
                var cptCheckBox = $(element).closest('.cpt-name-row').find('.cpt-name-checkbox');
                if ( cptCheckBox.is(':checked' ) ) {
                    var key   = $(element).data('cpt_type');
                    var value = $(element).val();
                    selectSpecificPosts[ key ] = value;
                }
            });

            $('.cpt-terms-select').each( (index, element) =>  {
                var key   = $(element).data('cpt_type');
                var tax   = $(element).data('tax_name');
                var value = $(element).val();
                if ( cptTerms[ key ] == undefined ) {
                    cptTerms[ key ] = {};
                }
                cptTerms[ key ][ tax ] = value;
            });

            $('.cpt-statuses-select').each( (index, element) =>  {
                var key   = $(element).data('cpt_type');
                var value = $(element).val();
                cptStatuses[ key ] = value;
            });

            $('.cpt-authors-select').each( (index, element) =>  {
                var key   = $(element).data('cpt_type');
                var value = $(element).val();
                cptAuthors[ key ] = value;
            });

            $('.cpt-start-date-select').each( (index, element) =>  {
                var key   = $(element).data('cpt_type');
                var value = $(element).val();
                cptStartDate[ key ] = value;
            });

            $('.cpt-end-date-select').each( (index, element) =>  {
                var key   = $(element).data('cpt_type');
                var value = $(element).val();
                cptEndDate[ key ] = value;
            });

            var data = {
                paged: paged,
                action: localize_vars.findImagesInPostsAction,
                nonce: localize_vars.nonce,
                cpt_name: postTypes,
                cpt_select_type: selectType,
                cpt_specific_posts: selectSpecificPosts,
                cpt_name_terms: cptTerms,
                cpt_statuses: cptStatuses,
                cpt_authors: cptAuthors,
                cpt_start_date: cptStartDate,
                cpt_end_date: cptEndDate,
            };
            $('.step-4').collapse('hide');
            this.toggleLoader( 'found-images', 'show' );
            $.ajax({
                method: 'POST',
                url: localize_vars.ajaxUrl,
                data: data,
                success: ( resp ) => {
                    if ( ! resp.success && resp?.data?.message ) {
                        this.showToast( resp.data.message, 'bg-' + resp.data.status );
                        $('#modal-found-images-watermarks-template').modal('hide');
                        return;
                    }
                    if ( resp?.data?.result ) {
                        var foundImagesResult = resp['data']['result'];
                        var foundImagesModal  = $('#modal-found-images-watermarks-template');
                        var totalItems        = foundImagesResult['attachments_count'];
                        var actionsRow        = foundImagesModal.find('.actions');
                        var totalPages        = Math.ceil( totalItems / 20 );

                        // 1) Fill in the resulted Images HTML.
                        actionsRow.find('.displaying-num').text( totalItems + ' items' );
                        this.updateListFoundImages( foundImagesResult['html'], actionsRow, paged, totalPages, false );

                        // 2) Store the founded images and store them as selected.
                        var foundImagesIDs  = Object.values( foundImagesResult['attachments_ids'] ).map( id => parseInt( id ) );
                        if ( paged === 1 ) {
                            this.selectedImagesCPTs = foundImagesIDs;
                            this.selectedImages     = foundImagesIDs;
                            this.foundImagesPages   = totalPages;
                        }
                        this.foundImages[ paged ] = foundImagesResult['html'];
                        if ( this.applyWatermarksTemplateData['imageSizes'] && this.applyWatermarksTemplateData['imageSizes'].length ) {
                            $('.step-4').collapse('show');
                        }
                    }
                },
                error: ( err ) => {
                    // console.log( 'error fetching images: ', err );
                    $('.select-errors-dialog').html( err.responseText ).dialog( 'open' );
                },
                complete: () => {
                    this.toggleLoader( 'found-images', 'hide' );
                }
            });
        }

        applyWatermarksTemplate( step = 0 ) {
            this.toggleLoader( '', 'show', true );
            var totalSteps = Math.ceil( this.selectedImages.length / parseInt( localize_vars.offsetLength ) );
            if ( step == 0 ) {
                $('.main-loader .loader-progress').val( 0 );
                $('.main-loader .loader-progress-num').removeClass('d-none').text('0%');
            }

            var data = {
                action: localize_vars.applyWatermarksTemplateAction,
                nonce: localize_vars.nonce,
                images: this.selectedImages,
                step: step,
                totalSteps: totalSteps,
                options: this.applyWatermarksTemplateData
            }

            $.ajax({
                method: 'POST',
                url: localize_vars.ajaxUrl,
                data: data,
                success: (resp) => {
                    if ( resp?.data && resp?.data?.message && resp.data.message.length ) {
                        if ( resp?.data?.errors && resp.data.errors.length ) {
                            this.combinedToast( resp.data.message, 'bg-' + resp.data.status, resp.data.errors );
                        } else {
                            this.showToast( resp?.data?.message, 'bg-' + resp.data.status );
                        }
                    }
                    if ( resp['success'] === false ) {
                        this.toggleLoader( '', 'hide' );
                    }
                    if ( resp['data']['status'] && resp['success'] ) {
                        if ( 'end' === resp['data']['step'] ) {
                            $('.main-loader .loader-progress').val(100);
                            $('.main-loader .loader-progress-num').text('100%');
                            setTimeout(() => {
                                this.toggleLoader( '', 'hide' );
                            }, 2000 );
                        } else {
                            var progress = Math.round( parseFloat( parseInt( resp['data']['step'] ) / totalSteps ) * 100 );
                            $('.main-loader .loader-progress').val( progress );
                            $('.main-loader .loader-progress-num').text( progress + '%' );
                            this.applyWatermarksTemplate( resp['data']['step'] );
                        }
                    }
                },
                error: (err) => {
                    // console.log( 'error:', err );
                    if ( err?.data?.message ) {
                        this.showToast( err.data.message, 'bg-danger' );
                    }
                }
            });
        }

        loading( btn, starting = true ) {
            // All Buttons.
            if ( starting ) {
                btn.addClass('disabled').prop('disabled', true );
                btn.siblings('.spinner').addClass('is-active');
            } else {
                btn.removeClass('disabled').prop('disabled', false );
                btn.siblings('.spinner').removeClass('is-active disabled');
            }
        }

        toggleLoader( cpt = '', action, progress = false ) {
            if ( cpt == '' ) {
                var loader = $('.main-loader');
            } else if ( cpt == 'found-images' ) {
                var loader = $('.selected-images-watermarks-template-modal').find('.loader');
            } else {
                var loader = $('#all-posts-' + cpt ).find('.loader');
            }
            if ( 'show' == action ) {
                loader.show();
            } else if ( 'hide' == action ) {
                loader.hide();
            }

            if ( progress ) {
                loader.find( '.loader-progress').removeClass('d-none');
                loader.find( '.loader-progress-num').removeClass('d-none');
            } else {
                loader.find( '.loader-progress').addClass('d-none');
                loader.find( '.loader-progress-num').addClass('d-none');
            }

        }

        updateListPostsTable( cpt, posts, checkSaved = false ) {
            var wrapper   = $( '#all-posts-' + cpt );
            var listPosts = `<tbody id="the-list-` + cpt + `">`;
            wrapper.find('.wp-list-table').find('tbody').remove();
            for ( let postID in posts ) {
                var postData = posts[ postID ];
                if ( this.savedPosts[ cpt ] && this.savedPosts[ cpt ].includes( postData.id ) ) {
                    postData.isChecked = true;
                } else {
                    postData.isChecked = false;
                }
                listPosts += this.fetchedPostRow( cpt, postData );
            }
            listPosts += '</tbody';
            wrapper.find('.wp-list-table').append( listPosts );

        }

        fetchedPostRow( cpt, post ) {
            var postRow = `<tr id="post-` + post.id + `" class="iedit all-posts-list-row">
                <th scope="row" class="check-column">
                    <input ` + ( post.isChecked ? 'checked' : '' ) + ` data-cpt="` + cpt + `" type="checkbox" class="cb-select-all cb-select-all-post-` + cpt + `" name="cb-select-all-post-` + cpt + `[]" id="cb-select-all-` + cpt + `-` + post.id + `" data-id="` + post.id + `">
                </th>
                <td class="title column-title column-primary page-title overflow-hidden" data-colname="Title">
                    <strong class="mt-1"><a href="` + post.edit_link + `" target="_blank" >` + post.title + `</a></strong>
                    <button type="button" class="toggle-row"></button>
                </td>
                <td class="date column-date page-date" data-colname="Date">
                    <strong>` + post.date + `</strong>
                </td>
            </tr>`
            return postRow;
        }


        showToast( toastMsg, bgColor = 'bg-primary', is_multiple = false ) {
            var toast = $('.' + localize_vars['classes_prefix'] + '-msgs-toast' );
            toast.removeClass( (index, className) => {
                return (className.match (/(^|\s)bg-\S+/g) || []).join(' ');
            });
            var html = '';
            if ( ! is_multiple ) {
                html = '<p>' + toastMsg + '</p>';
            } else {
                html = '<ul class="toast-notice-list p-4">'
                toastMsg.forEach( ( msg ) => {
                    html += '<li class="notice-item"><p> - ' + msg + '</p></li>';
                });
                html += '</ul>';
            }
            toast.addClass( bgColor ).find('.toast-body').html( html );
            toast.toast({
                autohide: false
            });
            toast.toast('show');
        }

        combinedToast( toastMsg, bgColor = 'bg-primary', errors = [] ) {
            var toast = $('.' + localize_vars['classes_prefix'] + '-msgs-toast' );
            toast.removeClass( (index, className) => {
                return (className.match (/(^|\s)bg-\S+/g) || []).join(' ');
            });
            var html = '<p>' + toastMsg + '</p>';

            if ( errors.length ) {
                html += '<ul class="toast-notice-list p-4 bg-danger mt-4 overflow-scroll" style="max-height:600px;">'
                errors.forEach( ( msg ) => {
                    html += '<li class="notice-item"><p> - ' + msg + '</p></li>';
                });
                html += '</ul>';
            }

            toast.addClass( bgColor ).find('.toast-body').html( html );
            toast.toast({
                autohide: false
            });
            toast.toast('show');
        }
    }

    function taxonomyTermsSelect2( id, cpt, tax ) {
        var target = $('#' + id );
        if ( ! target.length ) {
            return;
        }
		target.select2(
			{
				placeholder: localize_vars.labels.search_term,
				width: '200px',
				cache: true,
                multiple: false,
                allowClear: true,
				ajax: {
					method: 'post',
					url: localize_vars.ajaxUrl,
					dataType: 'json',
					delay: 500,
					data: function( params ) {
						return {
							term: params.term,
							cpt: cpt,
                            tax: tax,
							action: localize_vars.searchCPTTermsAction
						}
					},
					processResults: function( result ) {
						var options = [];
						if ( result.data.length ) {
                            options = result.data;
						}
						return {
							results: options
						}
					}
				},
				minimumInputLength: 3
			}
		);
	}

})(jQuery);
