/**
 * @file assets/js/adminjs/repeater/mbs-repeater.js
 * MBS.Repeater — format row add/remove/cover/audio upload
 * Component of admin-repeater.js — extracted Session 94.
 * Dependency: mbs-admin-repeater (namespace initializer).
 * @package MyBookShowroom
 */

/**
 * @file assets/js/adminjs/admin-repeater.js
 * Format/Pricing repeater — add/remove rows, cover and audio upload, audiobook fields; validation deferred to admin-validation.js.
 * @package MyBookShowroom
 * @since   1.0.0
 */

(function( MBS, $, undefined ) {
	'use strict';
	var __ = wp.i18n.__;
	var escHtml = MBS_AdminUtils.escHtml;

	MBS.Repeater = {
		init: function() {
			this.bindAddRow();
			this.bindRemoveRow();
			this.bindFormatChange();
			this.bindMediaUpload();
			this.bindAudioUpload();
			this.bindSpinningVideoUpload();
			this.bindCollapseToggle();
			this.bindHeaderSync();
			this.initCollapseState();
			this.bindExpandCollapseAll();
			this.bindCollapseStatePersistence();
			this._sortable = MBS.SortableList.create( {
				container:        '#mbs-formats-rows',
				itemSelector:     '.mbs-format-row',
				handleSelector:   '.mbs-drag-handle',
				controlsSelector: '.mbs-reorder-controls',
				upSelector:       '.mbs-reorder-move-up',
				downSelector:     '.mbs-reorder-move-down',
				placeholderClass: 'mbs-sortable-placeholder',
				onReorder: function() { MBS.Repeater.updateSortOrderInputs(); }
			} );
			// Validation (ISBN, ASIN, Price) is handled by admin-validation.js.
		},

		bindAddRow: function() {
			$(document).on('click', '.mbs-add-format-row', function(e) {
				e.preventDefault();

				const $container = $('#mbs-formats-rows');

				const $template = $('#formats-row-template').clone()
					.removeAttr('id')
					.removeClass('mbs-format-row-template')
					.show();

				const rowCount = $container.find('.mbs-format-row').length;

				$template.find('input, select').each(function() {
					const name = $(this).attr('name');
					if (name) $(this).attr('name', name.replace('[]', '[' + rowCount + ']'));
					$(this).val('');
				});

				// Set data-row-index on the buy links container so MBS.FormatBuyLinks
				// can build correctly-named field arrays for this new row.
				$template.find('.mbs-format-buy-links-rows').attr('data-row-index', rowCount);
				// PLG-008: Also update the buy-link template div ID so that
				// MBS.FormatBuyLinks.bindAddBuyLink can find '#fmt-buy-link-row-template-{N}'.
				$template.find('[id^="fmt-buy-link-row-template-"]').attr('id', 'fmt-buy-link-row-template-' + rowCount);

				// Default new rows to eBook — most common format type.
				// PHP template already defaults to 'ebook'; JS override handles
				// the val('') clear above.
				$template.find('.mbs-format-select').val('ebook');

				// Expand the new row before appending so the body is visible.
				$template.find('.mbs-format-row').addClass('mbs-format-row--open');
				$template.find('.mbs-format-row-toggle').attr('aria-expanded', 'true');

				$container.append($template);
				$template.find('.mbs-format-select').trigger('change');
				MBS.Repeater.updateSortOrderInputs();
				// Refresh sortable (or arrow boundary states) after new row appended.
				if ( MBS.Repeater._sortable ) {
					MBS.Repeater._sortable.refresh();
				}

			});
		},

		bindRemoveRow: function() {
			$(document).on('click', '.mbs-remove-format-row', function(e) {
				e.preventDefault();
				if (window.confirm(__('Remove this format?', 'my-book-showroom'))) {
				$(this).closest('.mbs-format-row').remove();
				MBS.Repeater.updateSortOrderInputs();
				if ( MBS.Repeater._sortable ) { MBS.Repeater._sortable.refreshButtons(); }
			}
			});
		},

		bindFormatChange: function() {
			$(document).on('change', '.mbs-format-select', function() {
				const format = $(this).val();
				const row    = $(this).closest('.mbs-format-row, .mbs-format-row-template');

				// Custom label: shown only when 'other'
				row.find('.mbs-custom-label').toggle(format === 'other');

				// Audiobook-only fields: narrator, duration, audio sample
				row.find('.mbs-field-audiobook-only').toggle(format === 'audiobook');

				// eBook-only fields: file format (EPUB/MOBI/PDF)
				row.find('.mbs-field-ebook-only').toggle(format === 'ebook');

				// Page count: all formats except audiobook (and empty)
				row.find('.mbs-field-no-audiobook').toggle(format !== '' && format !== 'audiobook');

				// Format-required hint: visible only when no format is selected.
				row.find('.mbs-format-required-hint').toggle(format === '');

				// Cover size hint — swap text based on whether the format is audio.
				const $hint = row.find('.mbs-cover-hint');
				if ( $hint.length ) {
					$hint.text( /audio/i.test( format ) ? $hint.data('hint-audio') : $hint.data('hint-portrait') );
				}
			});
		},

		bindMediaUpload: function() {
			// One frame instance, rebound per-click so the 'select' handler always
			// closes over the correct row reference (fixes pre-existing scoping bug).
			let mediaFrame;
			$(document).on('click', '.mbs-upload-cover', function(e) {
				e.preventDefault();
				const button = $(this);
				const row    = button.closest('.mbs-format-row');

				if (!mediaFrame) {
					mediaFrame = wp.media({
						title:    __( 'Select Format Cover', 'my-book-showroom' ),
						button:   { text: __( 'Use this image', 'my-book-showroom' ) },
						multiple: false
					});
				}

				// Rebind so 'select' always references the current row/button.
				mediaFrame.off('select').on('select', function() {
					const attachment = mediaFrame.state().get('selection').first().toJSON();
					let preview = row.find('.mbs-cover-preview');
					if (preview.length === 0) {
						preview = $('<div class="mbs-cover-preview"><img src="" alt="" style="max-width:80px;display:block;margin-bottom:4px;"><button type="button" class="button mbs-remove-cover">' + escHtml( __( 'Remove', 'my-book-showroom' ) ) + '</button></div>');
						button.after(preview);
					}
					preview.find('img').attr('src', attachment.url);
					button.hide();
					row.find('input[name^="mbs_cover_image_id"]').val(attachment.id);
				});

				mediaFrame.open();
			});

			$(document).on('click', '.mbs-remove-cover', function() {
				const row = $(this).closest('.mbs-format-row');
				row.find('.mbs-cover-preview').remove();
				row.find('.mbs-upload-cover').show();
				row.find('input[name^="mbs_cover_image_id"]').val('');
			});
		},

		bindAudioUpload: function() {
			let audioFrame;
			$(document).on('click', '.mbs-upload-audio-sample', function(e) {
				e.preventDefault();
				const button = $(this);
				const row    = button.closest('.mbs-format-row');

				if (!audioFrame) {
					audioFrame = wp.media({
						title:    __( 'Select Audio File', 'my-book-showroom' ),
						button:   { text: __( 'Use this file', 'my-book-showroom' ) },
						multiple: false,
						library:  { type: 'audio' }
					});
				}

				audioFrame.off('select').on('select', function() {
					const attachment = audioFrame.state().get('selection').first().toJSON();
					row.find('input[name^="mbs_audio_sample_id"]').val(attachment.id);
					row.find('.mbs-audio-sample-name').text(attachment.filename || attachment.title).show();
					button.text( __( 'Change Audio File', 'my-book-showroom' ) );
					row.find('.mbs-remove-audio-sample').show();
				});

				audioFrame.open();
			});

			$(document).on('click', '.mbs-remove-audio-sample', function() {
				const row = $(this).closest('.mbs-format-row');
				row.find('input[name^="mbs_audio_sample_id"]').val('');
				row.find('.mbs-audio-sample-name').text('').hide();
				row.find('.mbs-upload-audio-sample').text(__( 'Select Audio File', 'my-book-showroom' ));
				$(this).hide();
			});
		},

		bindSpinningVideoUpload: function() {
			let spinFrame;
			$(document).on('click', '.mbs-upload-spinning-video', function(e) {
				e.preventDefault();
				const button  = $(this);
				const wrapper = button.closest('.mbs-video-uploader');

				if (!spinFrame) {
					spinFrame = wp.media({
						title:    __( 'Select Spinning Book Video', 'my-book-showroom' ),
						button:   { text: __( 'Use this video', 'my-book-showroom' ) },
						multiple: false,
						library:  { type: 'video' }
					});
				}

				spinFrame.off('select').on('select', function() {
					const attachment = spinFrame.state().get('selection').first().toJSON();
					wrapper.find('.mbs-spinning-video-id').val(attachment.id);
					wrapper.find('.mbs-spinning-video-name').text(attachment.filename || attachment.title).show();
					button.text( __( 'Replace Video', 'my-book-showroom' ) );
					wrapper.find('.mbs-remove-spinning-video').show();
				});

				spinFrame.open();
			});

			$(document).on('click', '.mbs-remove-spinning-video', function() {
				const wrapper = $(this).closest('.mbs-video-uploader');
				wrapper.find('.mbs-spinning-video-id').val('');
				wrapper.find('.mbs-spinning-video-name').text('').hide();
				wrapper.find('.mbs-upload-spinning-video').text( __( 'Upload Video', 'my-book-showroom' ) );
				$(this).hide();
			});
		},

		/**
		 * Toggle row open/closed when the header bar is clicked.
		 * Clicks on the Remove button are ignored (handled by bindRemoveRow).
		 *
		 * @returns {void}
		 * @since 2.3.0
		 */
		bindCollapseToggle: function() {
			$(document).on('click', '.mbs-format-row-header', function( e ) {
				if ( $( e.target ).closest( '.mbs-remove-format-row, .mbs-reorder-move-up, .mbs-reorder-move-down, .mbs-drag-handle' ).length ) {
					return;
				}
				const $row    = $( this ).closest( '.mbs-format-row' );
				const isOpen  = $row.toggleClass( 'mbs-format-row--open' ).hasClass( 'mbs-format-row--open' );
				$( this ).find( '.mbs-format-row-toggle' ).attr( 'aria-expanded', isOpen ? 'true' : 'false' );
			});
		},

		/**
		 * Keep the header badge and meta summary in sync with field values.
		 * Fires on format select change, and on input into ISBN-13 and price fields.
		 *
		 * @returns {void}
		 * @since 2.3.0
		 */
		bindHeaderSync: function() {
			// Badge: update when format type changes.
			$(document).on( 'change', '.mbs-format-select', function() {
				const $row   = $( this ).closest( '.mbs-format-row' );
				const label  = $( this ).find( 'option:selected' ).text().trim() || __( 'New Format', 'my-book-showroom' );
				$row.find( '.mbs-format-row-badge' ).text( label );
			});
			// Meta: update when custom label, ISBN-13, or price changes.
			$(document).on( 'input change', '.mbs-custom-label, .mbs-isbn-field, input[name="mbs_price[]"]', function() {
				const $row = $( this ).closest( '.mbs-format-row' );
				MBS.Repeater.syncHeaderMeta( $row );
			});
		},

		/**
		 * Rebuild the header meta string (ISBN · $price) for a single row.
		 *
		 * @param {jQuery} $row The .mbs-format-row element.
		 * @returns {void}
		 * @since 2.3.0
		 */
		syncHeaderMeta: function( $row ) {
			const isbn  = $row.find( 'input[name="mbs_isbn13[]"]' ).val().trim();
			const price = $row.find( 'input[name="mbs_price[]"]' ).val().trim();
			const parts = [];
			if ( isbn )  { parts.push( isbn ); }
			if ( price ) { parts.push( '$' + price ); }
			$row.find( '.mbs-format-row-meta' ).text( parts.join( ' · ' ) );
		},

		/**
		 * Set initial collapse state on page load.
		 * First tries to restore the state that was saved before the last submit
		 * (written by saveCollapseState via bindCollapseStatePersistence).
		 * Falls back to: one saved row auto-expands; two or more start collapsed.
		 * Newly added rows are always expanded by bindAddRow().
		 *
		 * @returns {void}
		 * @since 2.3.0
		 */
		initCollapseState: function() {
			// Restore the pre-save open/closed state when returning from a save.
			if ( this.restoreCollapseState() ) { return; }
			// Fallback: auto-expand when there is only one format row.
			const $rows = $( '#mbs-formats-rows .mbs-format-row' );
			if ( $rows.length === 1 ) {
				$rows.first().addClass( 'mbs-format-row--open' );
				$rows.first().find( '.mbs-format-row-toggle' ).attr( 'aria-expanded', 'true' );
			}
		},

		/**
		 * Expand or collapse all format rows at once.
		 *
		 * @returns {void}
		 * @since 2.4.0
		 */
		bindExpandCollapseAll: function() {
			const self = this;

			$( document ).on( 'click', '.mbs-expand-all', function() {
				$( '#mbs-formats-rows .mbs-format-row' ).each( function() {
					$( this ).addClass( 'mbs-format-row--open' );
					$( this ).find( '.mbs-format-row-toggle' ).attr( 'aria-expanded', 'true' );
				} );
			} );

			$( document ).on( 'click', '.mbs-collapse-all', function() {
				$( '#mbs-formats-rows .mbs-format-row' ).each( function() {
					$( this ).removeClass( 'mbs-format-row--open' );
					$( this ).find( '.mbs-format-row-toggle' ).attr( 'aria-expanded', 'false' );
				} );
			} );
		},

		/**
		 * Write the current open/closed state of all format rows to sessionStorage
		 * so it can be restored after a save-and-reload cycle.
		 * Keyed by post ID to avoid cross-post collisions.
		 * Called on WordPress post-form submit via bindCollapseStatePersistence().
		 *
		 * @returns {void}
		 * @since 2.5.0
		 */
		saveCollapseState: function() {
			var postId = $( '#post_ID' ).val();
			if ( ! postId || typeof sessionStorage === 'undefined' ) { return; }
			var openIndices = [];
			$( '#mbs-formats-rows .mbs-format-row' ).each( function( i ) {
				if ( $( this ).hasClass( 'mbs-format-row--open' ) ) {
					openIndices.push( i );
				}
			} );
			try {
				sessionStorage.setItem( 'mbs_format_state_' + postId, JSON.stringify( openIndices ) );
			} catch ( e ) {}
		},

		/**
		 * Read the persisted open/closed state from sessionStorage and apply it.
		 * Clears the stored entry immediately after reading (one-shot restore).
		 * Returns true if state was successfully restored, false if nothing stored.
		 *
		 * @returns {boolean}
		 * @since 2.5.0
		 */
		restoreCollapseState: function() {
			var postId = $( '#post_ID' ).val();
			if ( ! postId || typeof sessionStorage === 'undefined' ) { return false; }
			var stored;
			try {
				stored = sessionStorage.getItem( 'mbs_format_state_' + postId );
				sessionStorage.removeItem( 'mbs_format_state_' + postId );
			} catch ( e ) { return false; }
			if ( ! stored ) { return false; }
			var openIndices;
			try { openIndices = JSON.parse( stored ); } catch ( e ) { return false; }
			if ( ! Array.isArray( openIndices ) || ! openIndices.length ) { return false; }
			var $rows = $( '#mbs-formats-rows .mbs-format-row' );
			openIndices.forEach( function( idx ) {
				var $row = $rows.eq( idx );
				if ( $row.length ) {
					$row.addClass( 'mbs-format-row--open' );
					$row.find( '.mbs-format-row-toggle' ).attr( 'aria-expanded', 'true' );
				}
			} );
			return true;
		},

		/**
		 * Bind state persistence to the WordPress post-form submit event.
		 * Fires saveCollapseState() just before the browser POSTs the form so
		 * the open/closed state reaches sessionStorage before the page unloads.
		 *
		 * @returns {void}
		 * @since 2.5.0
		 */
		bindCollapseStatePersistence: function() {
			$( document ).on( 'submit', '#post', function() {
				MBS.Repeater.saveCollapseState();
			} );
		},

		/**
		 * Write the current DOM position of each row into its hidden
		 * mbs_format_sort_order[] input so the PHP save handler persists it.
		 * Also the onReorder callback passed to MBS.SortableList.create().
		 *
		 * @returns {void}
		 * @since 2.4.0
		 */
		updateSortOrderInputs: function() {
			$( '#mbs-formats-rows .mbs-format-row' ).each( function( i ) {
				$( this ).find( 'input[name="mbs_format_sort_order[]"]' ).val( i );
			} );
		},


	};

	MBS.Repeater.init();

})( window.MBS = window.MBS || {}, jQuery );
