/* global BATAI, wp */
( function () {
	'use strict';

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

	var apiFetch = wp && wp.apiFetch ? wp.apiFetch : null;

	/**
	 * POST helper. Uses wp.apiFetch when available, otherwise fetch().
	 *
	 * @param {string} path Path relative to the namespace root.
	 * @param {Object} body Request body.
	 * @return {Promise<Object>} Parsed JSON.
	 */
	function post( path, body ) {
		if ( apiFetch ) {
			return apiFetch( {
				url: BATAI.root + path,
				method: 'POST',
				headers: { 'X-WP-Nonce': BATAI.nonce },
				data: body || {},
			} );
		}
		return fetch( BATAI.root + path, {
			method: 'POST',
			headers: {
				'Content-Type': 'application/json',
				'X-WP-Nonce': BATAI.nonce,
			},
			body: JSON.stringify( body || {} ),
		} ).then( function ( r ) {
			return r.json().then( function ( data ) {
				if ( ! r.ok ) {
					throw data;
				}
				return data;
			} );
		} );
	}

	/**
	 * GET helper.
	 *
	 * @param {string} path Path (with query string) relative to the namespace root.
	 * @return {Promise<Object>} Parsed JSON.
	 */
	function get( path ) {
		if ( apiFetch ) {
			return apiFetch( {
				url: BATAI.root + path,
				method: 'GET',
				headers: { 'X-WP-Nonce': BATAI.nonce },
			} );
		}
		return fetch( BATAI.root + path, {
			headers: { 'X-WP-Nonce': BATAI.nonce },
		} ).then( function ( r ) {
			return r.json().then( function ( data ) {
				if ( ! r.ok ) {
					throw data;
				}
				return data;
			} );
		} );
	}

	function sprintf1( template, value ) {
		return template.replace( '%d', value );
	}

	/* --------------------- Media library: single alt -------------------- */

	function initAltButtons() {
		document.addEventListener( 'click', function ( e ) {
			var btn = e.target.closest ? e.target.closest( '.batai-alt' ) : null;
			if ( ! btn ) {
				return;
			}
			e.preventDefault();
			var id = parseInt( btn.getAttribute( 'data-attachment-id' ), 10 );
			var status = btn.parentNode.querySelector( '.batai-alt-status' );
			var original = btn.textContent;
			btn.disabled = true;
			btn.textContent = BATAI.i18n.generating;

			post( '/alt-text', { attachment_id: id, apply: true } )
				.then( function ( data ) {
					var field =
						document.getElementById( 'attachments-' + id + '-alt' ) ||
						document.querySelector( '[data-setting="alt"] input, [data-setting="alt"] textarea' );
					if ( field ) {
						field.value = data.text;
						field.dispatchEvent( new Event( 'change', { bubbles: true } ) );
					}
					if ( status ) {
						status.textContent = '✓ ' + data.text;
					}
				} )
				.catch( function ( err ) {
					if ( status ) {
						showError( status, err );
					}
				} )
				.finally( function () {
					btn.disabled = false;
					btn.textContent = original;
				} );
		} );
	}

	/* ----------------------- AI connection test ------------------------- */

	function initTestConnection() {
		var btn = document.getElementById( 'batai-test-conn' );
		if ( ! btn ) {
			return;
		}
		var result = document.querySelector( '.batai-test-result' );

		btn.addEventListener( 'click', function () {
			btn.disabled = true;
			result.className = 'batai-test-result';
			result.textContent = BATAI.i18n.testing;

			post( '/test-connection', {} )
				.then( function ( data ) {
					result.className = 'batai-test-result is-ok';
					result.textContent =
						'✓ ' + sprintf1( BATAI.i18n.aiReplied, data.elapsed_ms ) + ' “' + data.response + '”';
				} )
				.catch( function ( err ) {
					result.className = 'batai-test-result is-error';
					result.textContent = '✗ ' + ( ( err && err.error ) || BATAI.i18n.error );
				} )
				.finally( function () {
					btn.disabled = false;
				} );
		} );
	}

	/* --------------------------- Audit table ---------------------------- */

	var audit = {
		page: 1,
		pages: 1,
		filter: 'missing',
	};

	function auditEls() {
		return {
			wrap: document.getElementById( 'batai-audit' ),
			rows: document.getElementById( 'batai-rows' ),
			filter: document.getElementById( 'batai-filter' ),
			load: document.getElementById( 'batai-load' ),
			more: document.getElementById( 'batai-more' ),
			all: document.getElementById( 'batai-check-all' ),
			count: document.querySelector( '.batai-selcount' ),
		};
	}

	function selectedIds() {
		var checks = document.querySelectorAll( '.batai-row-check:checked' );
		return Array.prototype.map.call( checks, function ( c ) {
			return parseInt( c.value, 10 );
		} );
	}

	function updateSelCount() {
		var els = auditEls();
		if ( els.count ) {
			els.count.textContent = sprintf1( BATAI.i18n.selected, selectedIds().length );
		}
	}

	function statusBadge( item ) {
		if ( item.generated ) {
			return '<span class="batai-badge is-gen">' + BATAI.i18n.sPlugin + '</span>';
		}
		if ( item.alt === '' ) {
			return '<span class="batai-badge is-missing">' + BATAI.i18n.sMissing + '</span>';
		}
		return '<span class="batai-badge is-pro">' + BATAI.i18n.sOk + '</span>';
	}

	function esc( s ) {
		var d = document.createElement( 'div' );
		d.textContent = s == null ? '' : String( s );
		return d.innerHTML;
	}

	function renderRow( item ) {
		var els = auditEls();
		var tr = document.createElement( 'tr' );
		tr.setAttribute( 'data-id', item.id );
		tr.innerHTML =
			'<th class="check-column"><input type="checkbox" class="batai-row-check" value="' + item.id + '"></th>' +
			'<td>' + ( item.thumb ? '<img class="batai-thumb" src="' + esc( item.thumb ) + '" alt="">' : '—' ) + '</td>' +
			'<td class="batai-cell-file">' + esc( item.filename ) + '</td>' +
			'<td class="batai-cell-alt">' + ( item.alt ? esc( item.alt ) : '<em>—</em>' ) + '</td>' +
			'<td class="batai-cell-status">' + statusBadge( item ) + '</td>';
		els.rows.appendChild( tr );
	}

	function updateRow( id, text ) {
		var tr = document.querySelector( '#batai-rows tr[data-id="' + id + '"]' );
		if ( ! tr ) {
			return;
		}
		tr.querySelector( '.batai-cell-alt' ).innerHTML = esc( text );
		tr.querySelector( '.batai-cell-status' ).innerHTML =
			'<span class="batai-badge is-gen">' + BATAI.i18n.sPlugin + '</span>';
	}

	function loadImages( reset ) {
		var els = auditEls();
		els.load.disabled = true;
		els.load.textContent = BATAI.i18n.loading;

		get( '/images?filter=' + audit.filter + '&page=' + audit.page + '&per_page=20' )
			.then( function ( data ) {
				if ( reset ) {
					els.rows.innerHTML = '';
				}
				audit.pages = data.pages || 1;
				( data.items || [] ).forEach( renderRow );
				els.wrap.hidden = false;
				els.more.hidden = audit.page >= audit.pages;
				if ( ( data.items || [] ).length === 0 && reset ) {
					els.rows.innerHTML = '<tr><td colspan="5">' + BATAI.i18n.noImages + '</td></tr>';
				}
				updateSelCount();
			} )
			.catch( function ( err ) {
				window.alert( ( err && err.error ) || BATAI.i18n.error );
			} )
			.finally( function () {
				els.load.disabled = false;
				els.load.textContent = els.load.getAttribute( 'data-label' ) || els.load.textContent;
			} );
	}

	function initAudit() {
		var els = auditEls();
		if ( ! els.load ) {
			return;
		}
		els.load.setAttribute( 'data-label', els.load.textContent );

		els.load.addEventListener( 'click', function () {
			audit.filter = els.filter ? els.filter.value : 'missing';
			audit.page = 1;
			loadImages( true );
		} );

		els.more.addEventListener( 'click', function () {
			audit.page++;
			loadImages( false );
		} );

		if ( els.all ) {
			els.all.addEventListener( 'change', function () {
				document.querySelectorAll( '.batai-row-check' ).forEach( function ( c ) {
					c.checked = els.all.checked;
				} );
				updateSelCount();
			} );
		}

		document.addEventListener( 'change', function ( e ) {
			if ( e.target && e.target.classList && e.target.classList.contains( 'batai-row-check' ) ) {
				updateSelCount();
			}
		} );
	}

	/* ---------------------- Manual test mode (no AI) -------------------- */

	function initManual() {
		var btn = document.getElementById( 'batai-manual-apply' );
		if ( ! btn ) {
			return;
		}
		var input = document.getElementById( 'batai-manual-text' );
		var status = document.querySelector( '.batai-manual-status' );

		btn.addEventListener( 'click', function () {
			var text = ( input.value || '' ).trim();
			var ids = selectedIds();
			status.className = 'batai-manual-status';

			if ( text === '' ) {
				status.textContent = BATAI.i18n.noText;
				return;
			}
			if ( ids.length === 0 ) {
				status.textContent = BATAI.i18n.noSelection;
				return;
			}

			btn.disabled = true;
			status.textContent = BATAI.i18n.applying;

			post( '/manual', { text: text, ids: ids } )
				.then( function ( data ) {
					status.className = 'batai-manual-status is-ok';
					status.textContent = sprintf1( BATAI.i18n.appliedTo, data.applied );
					( data.ids || [] ).forEach( function ( id ) {
						updateRow( id, data.text );
					} );
				} )
				.catch( function ( err ) {
					status.className = 'batai-manual-status is-error';
					status.textContent = ( err && err.error ) || BATAI.i18n.error;
				} )
				.finally( function () {
					btn.disabled = false;
				} );
		} );
	}

	/* -------------------- AI for the selected images --------------------- */

	function initAiSelected() {
		var btn = document.getElementById( 'batai-ai-selected' );
		if ( ! btn ) {
			return;
		}
		var status = document.querySelector( '.batai-ai-selected-status' );

		btn.addEventListener( 'click', function () {
			var ids = selectedIds();
			status.className = 'batai-ai-selected-status';

			if ( ids.length === 0 ) {
				status.textContent = BATAI.i18n.noSelection;
				return;
			}

			btn.disabled = true;
			var doneCount = 0;
			var total = ids.length;
			var queue = ids.slice();

			function next() {
				if ( queue.length === 0 ) {
					status.className = 'batai-ai-selected-status is-ok';
					status.textContent = doneCount + ' / ' + total + ' ✓ ' + BATAI.i18n.done;
					btn.disabled = false;
					return;
				}
				var chunk = queue.splice( 0, 3 );
				status.textContent = doneCount + ' / ' + total + '…';

				post( '/bulk', { ids: chunk } )
					.then( function ( data ) {
						( data.processed || [] ).forEach( function ( item ) {
							doneCount++;
							updateRow( item.id, item.text );
						} );
						if ( data.error ) {
							status.className = 'batai-ai-selected-status is-error';
							status.innerHTML = '';
							showError( status, data );
							btn.disabled = false;
							return;
						}
						next();
					} )
					.catch( function ( err ) {
						status.className = 'batai-ai-selected-status is-error';
						status.innerHTML = '';
						showError( status, err );
						btn.disabled = false;
					} );
			}
			next();
		} );
	}

	/* ------------------------- Bulk generation -------------------------- */

	function initBulk() {
		var wrap = document.getElementById( 'batai-bulk' );
		if ( ! wrap ) {
			return;
		}
		var startBtn = document.getElementById( 'batai-bulk-start' );
		var stopBtn = document.getElementById( 'batai-bulk-stop' );
		var progress = wrap.querySelector( '.batai-progress' );
		var bar = wrap.querySelector( '.batai-progress-bar span' );
		var label = wrap.querySelector( '.batai-progress-label' );
		var log = wrap.querySelector( '.batai-log' );

		var processed = 0;
		var total = 0;
		var stopped = false;

		function scope() {
			var checked = wrap.querySelector( 'input[name="batai-scope"]:checked' );
			return checked ? checked.value : 'missing';
		}

		startBtn.addEventListener( 'click', function () {
			stopped = false;
			processed = 0;
			log.innerHTML = '';
			bar.style.width = '0%';
			total = scope() === 'all'
				? parseInt( wrap.getAttribute( 'data-total' ), 10 ) || 0
				: parseInt( wrap.getAttribute( 'data-missing' ), 10 ) || 0;
			startBtn.disabled = true;
			stopBtn.hidden = false;
			progress.hidden = false;
			label.textContent = '0 / ' + total;
			runBatch();
		} );

		stopBtn.addEventListener( 'click', function () {
			stopped = true;
			stopBtn.disabled = true;
			stopBtn.textContent = '…';
		} );

		function runBatch() {
			post( '/bulk', {
				batch: 5,
				scope: scope(),
				date_from: ( document.getElementById( 'batai-date-from' ) || {} ).value || '',
				date_to: ( document.getElementById( 'batai-date-to' ) || {} ).value || '',
			} )
				.then( function ( data ) {
					( data.processed || [] ).forEach( function ( item ) {
						processed++;
						var li = document.createElement( 'li' );
						li.textContent = '#' + item.id + ' — ' + item.text;
						log.appendChild( li );
					} );
					var remaining = data.remaining_total || 0;
					if ( total < processed + remaining ) {
						total = processed + remaining;
					}
					var pct = total ? Math.min( 100, Math.round( ( processed / total ) * 100 ) ) : 100;
					bar.style.width = pct + '%';
					label.textContent = processed + ' / ' + total;

					var more = ( data.processed || [] ).length > 0 && remaining > 0;
					if ( more && ! stopped ) {
						runBatch();
					} else {
						finish();
					}
				} )
				.catch( function ( err ) {
					var li = document.createElement( 'li' );
					li.className = 'batai-error';
					li.textContent = ( err && err.error ) || BATAI.i18n.error;
					log.appendChild( li );
					if ( err && err.upgrade_url ) {
						var a = document.createElement( 'a' );
						a.href = err.upgrade_url;
						a.target = '_blank';
						a.rel = 'noopener';
						a.textContent = ' ' + BATAI.i18n.upgrade;
						li.appendChild( a );
					}
					finish();
				} );
		}

		function finish() {
			label.textContent += '  ✓ ' + BATAI.i18n.done;
			startBtn.disabled = false;
			stopBtn.hidden = true;
			stopBtn.disabled = false;
			stopBtn.textContent = 'Stop';
		}
	}

	/* ------------------------------ Revert ------------------------------ */

	function initRevert() {
		var btn = document.getElementById( 'batai-revert' );
		if ( ! btn ) {
			return;
		}
		var status = document.querySelector( '.batai-revert-status' );

		btn.addEventListener( 'click', function () {
			if ( ! window.confirm( BATAI.i18n.confirm ) ) {
				return;
			}
			btn.disabled = true;
			var reverted = 0;

			function runBatch() {
				post( '/revert', { batch: 25 } )
					.then( function ( data ) {
						reverted += data.reverted || 0;
						if ( status ) {
							status.textContent = reverted + '…';
						}
						if ( ( data.reverted || 0 ) > 0 && ( data.remaining_total || 0 ) > 0 ) {
							runBatch();
						} else {
							if ( status ) {
								status.textContent = '✓ ' + reverted;
							}
							setTimeout( function () {
								window.location.reload();
							}, 700 );
						}
					} )
					.catch( function () {
						if ( status ) {
							status.textContent = BATAI.i18n.error;
						}
						btn.disabled = false;
					} );
			}
			runBatch();
		} );
	}

	/* ------------------- Page scanner (a11y + SEO) ----------------------- */

	var __ = ( window.wp && wp.i18n && wp.i18n.__ ) ? wp.i18n.__ : function ( s ) { return s; };

	/**
	 * Run all accessibility + SEO checks against a same-origin document.
	 *
	 * Each result: { level: 'fail'|'warn'|'pass'|'info', cat: 'a11y'|'seo',
	 *                label, items: [ { text, attachmentId? } ] }
	 *
	 * @param {Document} doc The scanned page document.
	 * @return {Array<Object>} results
	 */
	function runChecks( doc ) {
		var results = [];

		function add( level, cat, label, items ) {
			results.push( { level: level, cat: cat, label: label, items: items || [] } );
		}

		function short( el ) {
			var s = ( el.outerHTML || '' ).replace( /\s+/g, ' ' );
			return s.length > 110 ? s.slice( 0, 110 ) + '…' : s;
		}

		function attachmentIdOf( img ) {
			var m = ( img.className || '' ).match( /wp-image-(\d+)/ );
			return m ? parseInt( m[ 1 ], 10 ) : 0;
		}

		var imgs = [].slice.call( doc.querySelectorAll( 'img' ) );

		/* ---------------------------- A11Y ------------------------------ */

		// 1. Images with no alt attribute at all (WCAG 1.1.1).
		var noAlt = imgs.filter( function ( i ) {
			return ! i.hasAttribute( 'alt' );
		} );
		if ( noAlt.length ) {
			add( 'fail', 'a11y', __( 'Images without an alt attribute', 'bulk-alt-text-ai' ), noAlt.map( function ( i ) {
				return {
					text: ( i.getAttribute( 'src' ) || '' ).split( '/' ).pop() || short( i ),
					attachmentId: attachmentIdOf( i ),
				};
			} ) );
		} else {
			add( 'pass', 'a11y', __( 'Every image has an alt attribute', 'bulk-alt-text-ai' ) );
		}

		// 2. Images with an empty alt (fine if decorative — flag for review).
		var emptyAlt = imgs.filter( function ( i ) {
			return i.getAttribute( 'alt' ) === '';
		} );
		if ( emptyAlt.length ) {
			add( 'warn', 'a11y', __( 'Images with empty alt (OK only if decorative — review them)', 'bulk-alt-text-ai' ), emptyAlt.map( function ( i ) {
				return {
					text: ( i.getAttribute( 'src' ) || '' ).split( '/' ).pop() || short( i ),
					attachmentId: attachmentIdOf( i ),
				};
			} ) );
		}

		// 3. Links without an accessible name (WCAG 2.4.4).
		var badLinks = [].slice.call( doc.querySelectorAll( 'a[href]' ) ).filter( function ( a ) {
			if ( ( a.textContent || '' ).trim() !== '' ) {
				return false;
			}
			if ( ( a.getAttribute( 'aria-label' ) || '' ).trim() !== '' || a.getAttribute( 'aria-labelledby' ) ) {
				return false;
			}
			if ( ( a.getAttribute( 'title' ) || '' ).trim() !== '' ) {
				return false;
			}
			return ! a.querySelector( 'img[alt]:not([alt=""])' );
		} );
		add(
			badLinks.length ? 'fail' : 'pass',
			'a11y',
			badLinks.length
				? __( 'Links with no accessible text (screen readers announce nothing)', 'bulk-alt-text-ai' )
				: __( 'All links have an accessible name', 'bulk-alt-text-ai' ),
			badLinks.map( function ( a ) {
				return { text: short( a ) };
			} )
		);

		// 4. Form fields without a label (WCAG 3.3.2).
		var badFields = [].slice.call(
			doc.querySelectorAll( 'input:not([type=hidden]):not([type=submit]):not([type=button]), select, textarea' )
		).filter( function ( f ) {
			if ( f.getAttribute( 'aria-label' ) || f.getAttribute( 'aria-labelledby' ) || f.getAttribute( 'title' ) ) {
				return false;
			}
			if ( f.id && doc.querySelector( 'label[for="' + f.id.replace( /"/g, '\\"' ) + '"]' ) ) {
				return false;
			}
			return ! f.closest( 'label' );
		} );
		if ( badFields.length ) {
			add( 'fail', 'a11y', __( 'Form fields without a label', 'bulk-alt-text-ai' ), badFields.map( function ( f ) {
				return { text: short( f ) };
			} ) );
		}

		// 5. Heading structure (multiple/missing h1, skipped levels).
		var headings = [].slice.call( doc.querySelectorAll( 'h1,h2,h3,h4,h5,h6' ) );
		var h1s = headings.filter( function ( h ) {
			return h.tagName === 'H1';
		} );
		if ( h1s.length === 0 ) {
			add( 'fail', 'a11y', __( 'No <h1> heading on the page', 'bulk-alt-text-ai' ) );
		} else if ( h1s.length > 1 ) {
			add( 'warn', 'a11y', __( 'More than one <h1> heading', 'bulk-alt-text-ai' ), h1s.map( function ( h ) {
				return { text: ( h.textContent || '' ).trim().slice( 0, 80 ) };
			} ) );
		} else {
			add( 'pass', 'a11y', __( 'Exactly one <h1> heading', 'bulk-alt-text-ai' ) );
		}
		var skips = [];
		var prev = 0;
		headings.forEach( function ( h ) {
			var lvl = parseInt( h.tagName.slice( 1 ), 10 );
			if ( prev && lvl > prev + 1 ) {
				skips.push( { text: 'h' + prev + ' → h' + lvl + ' — “' + ( h.textContent || '' ).trim().slice( 0, 60 ) + '”' } );
			}
			prev = lvl;
		} );
		if ( skips.length ) {
			add( 'warn', 'a11y', __( 'Skipped heading levels (e.g. h2 → h4)', 'bulk-alt-text-ai' ), skips );
		}

		// 6. <html lang>.
		var lang = doc.documentElement.getAttribute( 'lang' );
		add(
			lang ? 'pass' : 'fail',
			'a11y',
			lang
				? __( 'Page declares a language', 'bulk-alt-text-ai' ) + ' (' + lang + ')'
				: __( 'Missing lang attribute on <html>', 'bulk-alt-text-ai' )
		);

		// 7. Iframes without a title.
		var badFrames = [].slice.call( doc.querySelectorAll( 'iframe' ) ).filter( function ( f ) {
			return ! ( f.getAttribute( 'title' ) || '' ).trim();
		} );
		if ( badFrames.length ) {
			add( 'warn', 'a11y', __( 'Iframes without a title', 'bulk-alt-text-ai' ), badFrames.map( function ( f ) {
				return { text: ( f.getAttribute( 'src' ) || short( f ) ).slice( 0, 100 ) };
			} ) );
		}

		/* ----------------------------- SEO ------------------------------ */

		var title = ( doc.title || '' ).trim();
		if ( ! title ) {
			add( 'fail', 'seo', __( 'Missing <title>', 'bulk-alt-text-ai' ) );
		} else if ( title.length > 60 ) {
			add( 'warn', 'seo', __( 'Title longer than 60 characters (may be cut in results)', 'bulk-alt-text-ai' ), [ { text: title } ] );
		} else {
			add( 'pass', 'seo', __( 'Title present and a good length', 'bulk-alt-text-ai' ), [ { text: title } ] );
		}

		var metaDesc = doc.querySelector( 'meta[name="description"]' );
		var descContent = metaDesc ? ( metaDesc.getAttribute( 'content' ) || '' ).trim() : '';
		if ( ! descContent ) {
			add( 'warn', 'seo', __( 'No meta description (search engines will pick their own snippet)', 'bulk-alt-text-ai' ) );
		} else if ( descContent.length < 50 || descContent.length > 160 ) {
			add( 'warn', 'seo', __( 'Meta description outside the 50–160 character sweet spot', 'bulk-alt-text-ai' ), [ { text: descContent } ] );
		} else {
			add( 'pass', 'seo', __( 'Meta description present and a good length', 'bulk-alt-text-ai' ) );
		}

		add(
			doc.querySelector( 'link[rel="canonical"]' ) ? 'pass' : 'info',
			'seo',
			doc.querySelector( 'link[rel="canonical"]' )
				? __( 'Canonical URL declared', 'bulk-alt-text-ai' )
				: __( 'No canonical URL (fine for most simple sites)', 'bulk-alt-text-ai' )
		);

		var ogTitle = doc.querySelector( 'meta[property="og:title"]' );
		var ogImage = doc.querySelector( 'meta[property="og:image"]' );
		add(
			( ogTitle && ogImage ) ? 'pass' : 'info',
			'seo',
			( ogTitle && ogImage )
				? __( 'Open Graph tags present (nice link previews)', 'bulk-alt-text-ai' )
				: __( 'Open Graph tags incomplete — link previews on social media may look plain', 'bulk-alt-text-ai' )
		);

		// Images without dimensions cause layout shift (Core Web Vitals).
		var noDims = imgs.filter( function ( i ) {
			return ! i.getAttribute( 'width' ) || ! i.getAttribute( 'height' );
		} );
		if ( noDims.length ) {
			add( 'warn', 'seo', __( 'Images without width/height attributes (causes layout shift)', 'bulk-alt-text-ai' ), noDims.slice( 0, 10 ).map( function ( i ) {
				return { text: ( i.getAttribute( 'src' ) || '' ).split( '/' ).pop() || short( i ) };
			} ) );
		} else if ( imgs.length ) {
			add( 'pass', 'seo', __( 'All images declare width/height', 'bulk-alt-text-ai' ) );
		}

		return results;
	}

	function renderReport( results ) {
		var report = document.getElementById( 'batai-scan-report' );
		var summary = report.querySelector( '.batai-scan-summary' );
		var out = report.querySelector( '.batai-scan-results' );
		var hasSeoPlugin = report.getAttribute( 'data-seo-plugin' ) === '1';

		var counts = { fail: 0, warn: 0, pass: 0, info: 0 };
		results.forEach( function ( r ) {
			counts[ r.level ]++;
		} );

		summary.innerHTML =
			'<span class="batai-pill is-fail">✗ ' + counts.fail + ' ' + esc( __( 'failed', 'bulk-alt-text-ai' ) ) + '</span>' +
			'<span class="batai-pill is-warn">⚠ ' + counts.warn + ' ' + esc( __( 'warnings', 'bulk-alt-text-ai' ) ) + '</span>' +
			'<span class="batai-pill is-pass">✓ ' + counts.pass + ' ' + esc( __( 'passed', 'bulk-alt-text-ai' ) ) + '</span>';

		var icons = { fail: '✗', warn: '⚠', pass: '✓', info: 'ℹ' };
		var order = { fail: 0, warn: 1, info: 2, pass: 3 };
		var cats = {
			a11y: __( 'Accessibility (WCAG)', 'bulk-alt-text-ai' ),
			seo: __( 'SEO signals', 'bulk-alt-text-ai' ),
		};

		out.innerHTML = '';
		[ 'a11y', 'seo' ].forEach( function ( cat ) {
			var section = document.createElement( 'div' );
			section.className = 'batai-scan-section';
			var h = document.createElement( 'h3' );
			h.textContent = cats[ cat ];
			section.appendChild( h );

			if ( cat === 'seo' && hasSeoPlugin ) {
				var note = document.createElement( 'p' );
				note.className = 'description';
				note.textContent = __( 'You have a dedicated SEO plugin active — it manages most of these. Shown for information only.', 'bulk-alt-text-ai' );
				section.appendChild( note );
			}

			results
				.filter( function ( r ) {
					return r.cat === cat;
				} )
				.sort( function ( a, b ) {
					return order[ a.level ] - order[ b.level ];
				} )
				.forEach( function ( r ) {
					var item = document.createElement( 'div' );
					item.className = 'batai-scan-item is-' + r.level;

					var head = document.createElement( 'p' );
					head.className = 'batai-scan-item-head';
					head.textContent = icons[ r.level ] + ' ' + r.label +
						( r.items.length ? ' (' + r.items.length + ')' : '' );
					item.appendChild( head );

					if ( r.items.length ) {
						var ul = document.createElement( 'ul' );
						r.items.slice( 0, 25 ).forEach( function ( it ) {
							var li = document.createElement( 'li' );
							var code = document.createElement( 'code' );
							code.textContent = it.text;
							li.appendChild( code );
							if ( it.attachmentId ) {
								li.appendChild( document.createTextNode( ' ' ) );
								var fix = document.createElement( 'button' );
								fix.type = 'button';
								fix.className = 'button button-small batai-alt';
								fix.setAttribute( 'data-attachment-id', String( it.attachmentId ) );
								fix.textContent = __( '✨ Fix with AI', 'bulk-alt-text-ai' );
								li.appendChild( fix );
								var st = document.createElement( 'span' );
								st.className = 'batai-alt-status';
								li.appendChild( st );
							}
							ul.appendChild( li );
						} );
						item.appendChild( ul );
					}
					section.appendChild( item );
				} );
			out.appendChild( section );
		} );

		report.hidden = false;
	}

	function initScan() {
		var start = document.getElementById( 'batai-scan-start' );
		if ( ! start ) {
			return;
		}
		var select = document.getElementById( 'batai-scan-page' );
		var status = document.querySelector( '.batai-scan-status' );
		var frameWrap = document.getElementById( 'batai-scan-frame-wrap' );
		var frame = document.getElementById( 'batai-scan-frame' );
		var report = document.getElementById( 'batai-scan-report' );

		start.addEventListener( 'click', function () {
			var url = select.value;
			if ( ! url ) {
				status.textContent = __( 'Choose a page first.', 'bulk-alt-text-ai' );
				return;
			}
			start.disabled = true;
			report.hidden = true;
			status.textContent = __( 'Loading page…', 'bulk-alt-text-ai' );
			frameWrap.hidden = false;

			var done = false;
			frame.onload = function () {
				if ( done ) {
					return;
				}
				done = true;
				var doc = null;
				try {
					doc = frame.contentDocument || frame.contentWindow.document;
					void doc.title; // Throws on cross-origin.
				} catch ( e ) {
					doc = null;
				}
				if ( ! doc || ! doc.body ) {
					status.textContent = __( 'Cannot scan this page: it is on a different origin or blocks framing.', 'bulk-alt-text-ai' );
					start.disabled = false;
					frameWrap.hidden = true;
					return;
				}
				status.textContent = __( 'Scanning…', 'bulk-alt-text-ai' );
				// Give late scripts a moment to settle, then audit.
				setTimeout( function () {
					renderReport( runChecks( doc ) );
					status.textContent = '';
					start.disabled = false;
					frameWrap.hidden = true;
					frame.src = 'about:blank';
				}, 400 );
			};
			frame.src = url;
		} );
	}

	function showError( el, err ) {
		var message = BATAI.i18n.error;
		if ( err && err.error ) {
			message = err.error;
		} else if ( err && err.message ) {
			message = err.message;
		}
		el.innerHTML = '';
		var span = document.createElement( 'span' );
		span.className = 'batai-error';
		span.textContent = message;
		el.appendChild( span );

		if ( err && err.upgrade_url ) {
			el.appendChild( document.createTextNode( ' ' ) );
			var a = document.createElement( 'a' );
			a.href = err.upgrade_url;
			a.target = '_blank';
			a.rel = 'noopener';
			a.textContent = BATAI.i18n.upgrade;
			el.appendChild( a );
		}
	}

	function ready( fn ) {
		if ( document.readyState !== 'loading' ) {
			fn();
		} else {
			document.addEventListener( 'DOMContentLoaded', fn );
		}
	}

	ready( function () {
		initAltButtons();
		initTestConnection();
		initAudit();
		initManual();
		initAiSelected();
		initBulk();
		initRevert();
		initScan();
	} );
} )();
