/* global smcFolders, wp, jQuery */
(function ($) {
	'use strict';

	if (typeof smcFolders === 'undefined') {
		return;
	}

	var SMC = {
		activeFolder : 0,
		folders      : smcFolders.folders || [],

		// ----------------------------------------------------------------
		// Bootstrap
		// ----------------------------------------------------------------

		init: function () {
			this.injectPanel();
			this.renderPanel();
			this.bindEvents();
			this.interceptQuery();
			this.initDragDrop();
			this.initBulkAssign();
		},

		// ----------------------------------------------------------------
		// Panel injection
		// ----------------------------------------------------------------

		injectPanel: function () {
			var $panel  = $('#smc-folders-panel');
			var $target = $('.media-frame-content');

			if ($target.length && $panel.length) {
				$panel.prependTo($target).show();
				$('body').addClass('smc-has-folders');
			}
		},

		// ----------------------------------------------------------------
		// Render folder tree
		// ----------------------------------------------------------------

		renderPanel: function () {
			// Preserve any active search term across re-renders (e.g. after folder CRUD).
			var searchVal = $( '#smc-folder-search' ).val() || '';

			var html = '<div class="smc-folders-header">'
				+ '<span class="smc-folders-title">' + smcFolders.i18n.folders + '</span>'
				+ '<button type="button" class="smc-btn-add-root" title="' + smcFolders.i18n.addFolder + '">+</button>'
				+ '</div>'
				+ '<div class="smc-folder-search-wrap">'
				+ '<input type="search" id="smc-folder-search" class="smc-folder-search" placeholder="' + smcFolders.i18n.searchFolders + '" value="' + $( '<span>' ).text( searchVal ).html() + '">'
				+ '</div>'
				+ '<ul class="smc-folder-list">'
				+ this.buildItem({ id: 0, name: smcFolders.i18n.allMedia, count: '', type: 'all' }, true)
				+ this.buildItem({ id: -1, name: smcFolders.i18n.uncategorized, count: '', type: 'uncategorized' }, false)
				+ this.buildItems(this.folders)
				+ '</ul>';

			html += '<div id="smc-bulk-bar" style="display:none;">'
				+ '<strong><span id="smc-bulk-count">0</span> ' + smcFolders.i18n.selected + '</strong>'
				+ '<span class="smc-bulk-hint">' + smcFolders.i18n.clickFolderToMove + '</span>'
				+ '</div>';

			$( '#smc-folders-panel' ).html( html );
			$( '#smc-folders-panel [data-id="' + this.activeFolder + '"]' ).first().addClass( 'smc-active' );

			// Re-apply search filter if there was an active query.
			if ( searchVal ) {
				this.filterFolders( searchVal.trim().toLowerCase() );
			}
		},

		buildItems: function (folders) {
			var self = this;
			var html = '';
			folders.forEach(function (folder) {
				html += self.buildItem(folder, false);
			});
			return html;
		},

		buildItem: function (folder, isActive) {
			var hasChildren = folder.children && folder.children.length > 0;
			var isSystem    = 'all' === folder.type || 'uncategorized' === folder.type;
			var activeClass = isActive ? ' smc-active' : '';

			var html = '<li class="smc-folder-item' + activeClass + (hasChildren ? ' has-children' : '') + '" data-id="' + folder.id + '">'
				+ '<span class="smc-toggle-wrap">'
				+ (hasChildren ? '<span class="smc-toggle dashicons dashicons-arrow-right-alt2"></span>' : '')
				+ '</span>'
				+ '<span class="dashicons dashicons-category smc-folder-icon"></span>'
				+ '<span class="smc-folder-name">' + $('<span>').text(folder.name).html() + '</span>';

			if ('' !== folder.count) {
				html += '<span class="smc-folder-count">' + folder.count + '</span>';
			}

			if (!isSystem) {
				html += '<span class="smc-folder-actions">'
					+ '<button type="button" class="smc-btn-rename" data-id="' + folder.id + '" title="' + smcFolders.i18n.rename + '">&#9998;</button>'
					+ '<button type="button" class="smc-btn-delete" data-id="' + folder.id + '" title="' + smcFolders.i18n.deleteFolder + '">&#215;</button>'
					+ '</span>';
			}

			if (hasChildren) {
				html += '<ul class="smc-folder-children">' + this.buildItems(folder.children) + '</ul>';
			}

			html += '</li>';
			return html;
		},

		// ----------------------------------------------------------------
		// Event bindings
		// ----------------------------------------------------------------

		bindEvents: function () {
			var self = this;

			// Select folder — or bulk-assign if images are currently selected.
			$(document).on('click', '#smc-folders-panel .smc-folder-item', function (e) {
				var $btn = $(e.target).closest('.smc-btn-rename, .smc-btn-delete, .smc-toggle');
				if ($btn.length) {
					return;
				}
				e.stopPropagation();
				var id  = parseInt( $(this).data('id'), 10 );
				var sel = self.getSelection();
				if ( sel && sel.length > 0 && 0 !== id ) {
					self.bulkAssignToFolder( id );
					return;
				}
				self.selectFolder(id, this);
			});

			// Toggle children open/close.
			$(document).on('click', '#smc-folders-panel .smc-toggle', function (e) {
				e.stopPropagation();
				$(this).closest('.smc-folder-item').toggleClass('open');
			});

			// Add root folder.
			$(document).on('click', '.smc-btn-add-root', function () {
				self.showPrompt(smcFolders.i18n.addFolder, smcFolders.i18n.folderName, '', function (name) {
					self.createFolder(name, 0);
				});
			});

			// Rename.
			$(document).on('click', '.smc-btn-rename', function (e) {
				e.stopPropagation();
				var id      = parseInt($(this).data('id'), 10);
				var current = $(this).closest('.smc-folder-item').find('.smc-folder-name').first().text();
				self.showPrompt(smcFolders.i18n.rename, smcFolders.i18n.newName, current, function (name) {
					if (name !== current) {
						self.renameFolder(id, name);
					}
				});
			});

			// Delete.
			$(document).on('click', '.smc-btn-delete', function (e) {
				e.stopPropagation();
				var id = parseInt($(this).data('id'), 10);
				self.showConfirm(smcFolders.i18n.deleteFolder, smcFolders.i18n.confirmDelete, function () {
					self.deleteFolder(id);
				});
			});

			// Modal OK.
			$(document).on('click', '#smc-modal-ok', function () {
				var cb = SMC._modalOkCb;
				if (typeof cb === 'function') {
					var val = $('#smc-modal-input').val().trim();
					cb(val);
				}
				self.closeModal();
			});

			// Modal Cancel / backdrop.
			$(document).on('click', '#smc-modal-cancel, .smc-modal-backdrop', function () {
				self.closeModal();
			});

			// Close modal on Escape.
			$(document).on('keydown', function (e) {
				if (27 === e.which && $('#smc-folder-modal').is(':visible')) {
					self.closeModal();
				}
			});

			// Folder search.
			$( document ).on( 'input', '#smc-folder-search', function () {
				self.filterFolders( $( this ).val().trim().toLowerCase() );
			} );
		},

		// ----------------------------------------------------------------
		// Folder search / filtering
		// ----------------------------------------------------------------

		filterFolders: function ( q ) {
			var $panel    = $( '#smc-folders-panel' );
			var $items    = $panel.find( '.smc-folder-item' );
			var $children = $panel.find( '.smc-folder-children' );
			var $real     = $items.filter( ':not([data-id="0"]):not([data-id="-1"])' );

			if ( !q ) {
				// No query — restore default CSS-driven state.
				$panel.removeClass( 'smc-searching' );
				$items.css( 'display', '' );
				$children.css( 'display', '' );
				return;
			}

			$panel.addClass( 'smc-searching' );

			// Hide all real folders and children to start clean.
			$real.hide();
			$children.hide();

			// Show folders whose name matches, and expand their ancestor chain.
			$real.each( function () {
				var name = $( this ).find( '.smc-folder-name' ).first().text().toLowerCase();
				if ( name.indexOf( q ) === -1 ) {
					return;
				}
				$( this ).show();
				// Reveal every ancestor folder item and its children container.
				$( this ).parents( '.smc-folder-item' ).show();
				$( this ).parents( '.smc-folder-children' ).show();
			} );
		},

		// ----------------------------------------------------------------
		// Bulk assign
		// ----------------------------------------------------------------

		getSelection: function () {
			try {
				var state = wp.media.frame.state();
				return state ? state.get( 'selection' ) : null;
			} catch ( e ) {
				return null;
			}
		},

		initBulkAssign: function () {
			var self = this;
			var bound = null;

			function updateBulkBar() {
				var sel   = self.getSelection();
				var count = sel ? sel.length : 0;
				if ( count > 0 ) {
					$( '#smc-bulk-count' ).text( count );
					$( '#smc-bulk-bar' ).show();
					$( 'body' ).addClass( 'smc-has-selection' );
				} else {
					$( '#smc-bulk-bar' ).hide();
					$( 'body' ).removeClass( 'smc-has-selection' );
				}
			}

			function bindToSelection() {
				var sel = self.getSelection();
				if ( ! sel || sel === bound ) { return; }
				if ( bound ) { bound.off( 'add remove reset', updateBulkBar ); }
				bound = sel;
				sel.on( 'add remove reset', updateBulkBar );
				updateBulkBar();
			}

			bindToSelection();
			if ( wp.media && wp.media.frame ) {
				wp.media.frame.on( 'state',          bindToSelection );
				wp.media.frame.on( 'content:render', bindToSelection );
			}
		},

		bulkAssignToFolder: function ( folderId ) {
			var self      = this;
			var sel       = this.getSelection();
			if ( ! sel || ! sel.length ) { return; }

			var ids       = sel.map( function ( m ) { return m.id; } );
			var apiFolder = ( -1 === folderId ) ? 0 : folderId;

			this.ajax( 'smc_bulk_assign_folder', { attachment_ids: ids, folder_id: apiFolder }, function ( err ) {
				if ( err ) { return; }

				// Clear Backbone selection model.
				sel.reset( [] );

				// Exit WordPress's "Bulk Select" mode by clicking its Cancel button.
				// It is always the non-primary button in the media toolbar.
				$( '.media-toolbar .button, .media-toolbar-primary .button' )
					.not( '.button-primary' )
					.first()
					.trigger( 'click' );

				self.refreshFolderCounts();
				self.refreshMedia();
			} );
		},

		// ----------------------------------------------------------------
		// Folder selection + media refresh
		// ----------------------------------------------------------------

		selectFolder: function (id, el) {
			this.activeFolder = id;
			$('#smc-folders-panel .smc-folder-item').removeClass('smc-active');
			if (el) {
				$(el).addClass('smc-active');
			}
			this.refreshMedia();
		},

		refreshMedia: function () {
			if ( !wp.media || !wp.media.frame ) {
				return;
			}
			try {
				var state   = wp.media.frame.state();
				var library = state && state.get( 'library' );
				if ( !library ) {
					return;
				}
				if ( this.activeFolder !== 0 ) {
					// Unset silently first so the subsequent set always fires a
					// change event — even when the folder ID hasn't changed.
					// Without this, Backbone skips the event and no requery happens.
					library.props.unset( 'smc_folder', { silent: true } );
					library.props.set( { smc_folder: this.activeFolder } );
				} else if ( library.props.has( 'smc_folder' ) ) {
					library.props.unset( 'smc_folder' );
				}
			} catch ( e ) {}
		},

		// ----------------------------------------------------------------
		// Intercept wp.media AJAX to inject smc_folder param
		// ----------------------------------------------------------------

		interceptQuery: function () {
			var self = this;
			// ajaxPrefilter runs before the transport is created, so options.data
			// modifications are guaranteed to reach the server. ajaxSend fires too
			// late — the transport may have already captured the data by then.
			$.ajaxPrefilter( function ( options ) {
				if ( typeof options.data !== 'string' ) {
					return;
				}
				if ( options.data.indexOf( 'action=query-attachments' ) === -1 ) {
					return;
				}
				if ( self.activeFolder !== 0 ) {
					options.data += '&smc_folder=' + encodeURIComponent( self.activeFolder );
				}
			} );
		},

		// ----------------------------------------------------------------
		// Drag & drop — image grid → folder panel
		// ----------------------------------------------------------------

		initDragDrop: function () {
			var self = this;

			// Make attachment items draggable as they arrive in the DOM.
			var observer = new MutationObserver( function () {
				$( '.attachment:not([draggable])' ).prop( 'draggable', true );
			} );
			observer.observe( document.body, { childList: true, subtree: true } );
			$( '.attachment:not([draggable])' ).prop( 'draggable', true );

			// Capture the attachment ID when a drag starts.
			// Also add a body class so CSS can force-hide the WordPress
			// "Drop files to upload" overlay (.uploader-window) — it intercepts
			// all dragenter events and sits on top of our folder panel.
			// display:none !important overrides jQuery's inline .show() call.
			$( document ).on( 'dragstart', '.attachment', function ( e ) {
				var id = $( this ).data( 'id' );
				if ( ! id ) { return; }
				e.originalEvent.dataTransfer.setData( 'text/plain', String( id ) );
				e.originalEvent.dataTransfer.effectAllowed = 'move';
				$( this ).addClass( 'smc-dragging' );
				$( 'body' ).addClass( 'smc-attachment-dragging' );
			} );

			$( document ).on( 'dragend', '.attachment', function () {
				$( this ).removeClass( 'smc-dragging' );
				$( 'body' ).removeClass( 'smc-attachment-dragging' );
				$( '#smc-folders-panel .smc-folder-item' ).removeClass( 'smc-drag-over' );
			} );

			// Highlight the folder the cursor is over.
			$( document ).on( 'dragover', '#smc-folders-panel .smc-folder-item', function ( e ) {
				e.preventDefault();
				e.stopPropagation();
				e.originalEvent.dataTransfer.dropEffect = 'move';
				$( '#smc-folders-panel .smc-folder-item' ).removeClass( 'smc-drag-over' );
				$( this ).addClass( 'smc-drag-over' );
			} );

			// Clear highlight when leaving the panel entirely.
			$( document ).on( 'dragleave', '#smc-folders-panel', function ( e ) {
				var related = e.originalEvent.relatedTarget;
				if ( ! related || ! $( related ).closest( '#smc-folders-panel' ).length ) {
					$( '#smc-folders-panel .smc-folder-item' ).removeClass( 'smc-drag-over' );
				}
			} );

			// Handle the drop.
			$( document ).on( 'drop', '#smc-folders-panel .smc-folder-item', function ( e ) {
				e.preventDefault();
				$( '#smc-folders-panel .smc-folder-item' ).removeClass( 'smc-drag-over' );

				var attachmentId = parseInt( e.originalEvent.dataTransfer.getData( 'text/plain' ), 10 );
				var folderId     = parseInt( $( this ).data( 'id' ), 10 );

				if ( ! attachmentId ) { return; }
				// "All Media" (0) is not a valid drop target.
				if ( 0 === folderId ) { return; }
				// "Uncategorized" (−1) means remove from all folders → pass 0 to the API.
				var apiFolder = ( -1 === folderId ) ? 0 : folderId;

				self.ajax( 'smc_assign_folder', { attachment_id: attachmentId, folder_id: apiFolder }, function ( err ) {
					if ( err ) { return; }
					// Update count badges without a full re-render.
					self.refreshFolderCounts();
					// Refresh the grid only when viewing a specific folder
					// (the dropped image may appear or disappear from the current view).
					if ( self.activeFolder !== 0 ) {
						self.refreshMedia();
					}
				} );
			} );
		},

		// Fetch fresh folder tree and update count badges in place.
		refreshFolderCounts: function () {
			var self = this;
			this.ajax( 'smc_get_folders', {}, function ( err, folders ) {
				if ( err || ! folders ) { return; }
				self.folders = folders;
				self.updateCountBadges( folders );
			} );
		},

		updateCountBadges: function ( folders ) {
			var self = this;
			folders.forEach( function ( folder ) {
				var $count = $( '#smc-folders-panel .smc-folder-item[data-id="' + folder.id + '"] > .smc-folder-count' );
				if ( $count.length ) {
					$count.text( folder.count );
				}
				if ( folder.children && folder.children.length ) {
					self.updateCountBadges( folder.children );
				}
			} );
		},

		// ----------------------------------------------------------------
		// Custom modal (avoids browser alert/confirm/prompt)
		// ----------------------------------------------------------------

		_modalOkCb: null,

		showPrompt: function (title, label, defaultVal, callback) {
			$('#smc-modal-title').text(title);
			$('#smc-modal-message').text(label);
			$('#smc-modal-input').val(defaultVal).show();
			$('#smc-modal-ok').text(smcFolders.i18n.ok);
			this._modalOkCb = function (val) {
				if (val) {
					callback(val);
				}
			};
			$('#smc-folder-modal').show();
			$('#smc-modal-input').trigger('focus');
		},

		showConfirm: function (title, message, callback) {
			$('#smc-modal-title').text(title);
			$('#smc-modal-message').text(message);
			$('#smc-modal-input').hide().val('');
			$('#smc-modal-ok').text(smcFolders.i18n.ok);
			this._modalOkCb = function () {
				callback();
			};
			$('#smc-folder-modal').show();
			$('#smc-modal-ok').trigger('focus');
		},

		closeModal: function () {
			$('#smc-folder-modal').hide();
			this._modalOkCb = null;
		},

		// ----------------------------------------------------------------
		// AJAX helpers
		// ----------------------------------------------------------------

		ajax: function (action, data, callback) {
			$.post(
				smcFolders.ajaxUrl,
				$.extend({ action: action, nonce: smcFolders.nonce }, data)
			).done(function (response) {
				if (response.success) {
					callback(null, response.data);
				} else {
					var msg = response.data && response.data.message ? response.data.message : smcFolders.i18n.error;
					callback(msg);
				}
			}).fail(function () {
				callback(smcFolders.i18n.error);
			});
		},

		// ----------------------------------------------------------------
		// CRUD operations
		// ----------------------------------------------------------------

		createFolder: function (name, parentId) {
			var self = this;
			this.ajax('smc_create_folder', { name: name, parent_id: parentId }, function (err, folder) {
				if (err) {
					self.showConfirm('Error', err, function () {});
					return;
				}
				if (parentId > 0) {
					self.insertIntoTree(self.folders, parentId, folder);
				} else {
					self.folders.push(folder);
				}
				self.renderPanel();
			});
		},

		renameFolder: function (id, name) {
			var self = this;
			this.ajax('smc_rename_folder', { id: id, name: name }, function (err) {
				if (err) {
					self.showConfirm('Error', err, function () {});
					return;
				}
				self.walkTree(self.folders, id, function (folder) {
					folder.name = name;
				});
				self.renderPanel();
			});
		},

		deleteFolder: function (id) {
			var self = this;
			this.ajax('smc_delete_folder', { id: id }, function (err) {
				if (err) {
					self.showConfirm('Error', err, function () {});
					return;
				}
				self.removeFromTree(self.folders, id);
				if (self.activeFolder === id) {
					self.activeFolder = 0;
				}
				self.renderPanel();
				self.refreshMedia();
			});
		},

		// ----------------------------------------------------------------
		// Tree helpers
		// ----------------------------------------------------------------

		walkTree: function (folders, id, cb) {
			folders.forEach(function (folder) {
				if (folder.id === id) {
					cb(folder);
					return;
				}
				if (folder.children && folder.children.length) {
					SMC.walkTree(folder.children, id, cb);
				}
			});
		},

		insertIntoTree: function (folders, parentId, newFolder) {
			folders.forEach(function (folder) {
				if (folder.id === parentId) {
					folder.children = folder.children || [];
					folder.children.push(newFolder);
					return;
				}
				if (folder.children && folder.children.length) {
					SMC.insertIntoTree(folder.children, parentId, newFolder);
				}
			});
		},

		removeFromTree: function (folders, id) {
			for (var i = 0; i < folders.length; i++) {
				if (folders[i].id === id) {
					folders.splice(i, 1);
					return true;
				}
				if (folders[i].children && folders[i].children.length) {
					if (SMC.removeFromTree(folders[i].children, id)) {
						return true;
					}
				}
			}
			return false;
		}
	};

	// ----------------------------------------------------------------
	// Init — wait for media library frame to be ready
	// ----------------------------------------------------------------

	$(function () {
		if (typeof wp === 'undefined' || typeof wp.media === 'undefined') {
			return;
		}

		var attempts = 0;
		var timer    = setInterval(function () {
			attempts++;
			if ($('.media-frame-content').length) {
				clearInterval(timer);
				SMC.init();
			} else if (attempts > 50) {
				clearInterval(timer);
			}
		}, 100);
	});

})(jQuery);
