/**
 * Compliance Guard — v0.7.394 Feature 7: in-editor live compliance check.
 *
 * A block-editor document panel that runs the SAME pending-content scan the
 * publish gate uses, so the merchant sees compliance problems before they
 * publish. Plain JS against the wp.* globals — no JSX, no build step.
 *
 * The server (ajax_editor_compliance_check -> gate_scan_pending_content) is
 * the source of truth; this file is a thin transport + UI wrapper.
 */
( function ( wp ) {
	'use strict';

	if ( ! wp || ! wp.plugins || ! wp.element || ! wp.data || ! wp.components ) {
		return;
	}

	var cfg = window.RPCA_EDITOR || {};
	var el = wp.element.createElement;
	var Fragment = wp.element.Fragment;
	var useState = wp.element.useState;
	var useEffect = wp.element.useEffect;
	var useCallback = wp.element.useCallback;
	var useRef = wp.element.useRef;
	var useSelect = wp.data.useSelect;
	var registerPlugin = wp.plugins.registerPlugin;

	// PluginDocumentSettingPanel moved from wp.editPost to wp.editor in WP
	// 6.6+. Resolve defensively so the panel works across versions; if it is
	// unavailable the script no-ops rather than crashing the editor.
	var Panel = ( wp.editor && wp.editor.PluginDocumentSettingPanel ) ||
		( wp.editPost && wp.editPost.PluginDocumentSettingPanel );
	if ( ! Panel || ! registerPlugin || ! useState || ! useSelect ) {
		return;
	}

	var Button = wp.components.Button;
	var Spinner = wp.components.Spinner;
	var Notice = wp.components.Notice;

	var ELIGIBLE = { post: true, page: true, product: true };
	var SEV = {
		critical: { label: 'Critical', color: '#b91c1c' },
		high: { label: 'High', color: '#c2410c' },
		medium: { label: 'Medium', color: '#b45309' },
		low: { label: 'Low', color: '#3f6212' }
	};
	function sevMeta( s ) {
		return SEV[ s ] || { label: s || 'Finding', color: '#475569' };
	}

	// Cheap non-cryptographic string hash (djb2) — only used to detect
	// whether content changed since the last completed check.
	function hashString( s ) {
		var h = 5381;
		var i = s.length;
		while ( i ) {
			h = ( ( h * 33 ) ^ s.charCodeAt( --i ) ) >>> 0;
		}
		return h.toString( 16 );
	}

	function plural( n ) {
		return 1 === n ? '' : 's';
	}

	function verdict( result, postStatus ) {
		if ( ! result || result.empty ) {
			return { status: 'info', text: 'Add content to this post, then run a compliance check.' };
		}
		var blocking = result.blocking || 0;
		var total = result.total || 0;
		// gateActive is computed server-side (gate enabled AND threshold not
		// 'off') — the single source of truth for "the gate will act".
		var gateOn = !! result.gateActive;
		var isLive = 'publish' === postStatus;
		if ( blocking > 0 && gateOn ) {
			if ( isLive ) {
				return {
					status: 'warning',
					text: blocking + ' blocking compliance issue' + plural( blocking ) +
						' found. This page is already published, so it stays live — but the compliance gate flags these and they should be fixed.'
				};
			}
			return {
				status: 'error',
				text: 'Publishing would be blocked. The compliance gate will hold this post as a draft until ' +
					blocking + ' blocking issue' + plural( blocking ) + ' ' + ( 1 === blocking ? 'is' : 'are' ) + ' resolved.'
			};
		}
		if ( blocking > 0 && ! gateOn ) {
			return {
				status: 'warning',
				text: blocking + ' blocking-severity issue' + plural( blocking ) +
					' found. The publish gate is currently off, so publishing is not blocked — but these are still compliance risks.'
			};
		}
		if ( total > 0 ) {
			return {
				status: 'warning',
				text: total + ' advisory compliance issue' + plural( total ) + ' found. None are at blocking severity.'
			};
		}
		return { status: 'success', text: 'No compliance issues found in this content.' };
	}

	function ComplianceCheckPanel() {
		// Mutable per-instance control state that runCheck reads/writes
		// without triggering re-renders (avoids React stale-closure bugs).
		var ctl = useRef( { inFlight: false, reqId: 0, lastHash: '' } );
		var prevSaving = useRef( false );
		var stPair = useState( { status: 'idle', result: null, checkedHash: '', error: '' } );
		var st = stPair[0];
		var setSt = stPair[1];

		// Live editor signature — re-renders the panel as content changes so
		// the "content changed" indicator stays current.
		var live = useSelect( function ( select ) {
			var ed = select( 'core/editor' );
			if ( ! ed ) {
				return { sig: '', postType: '', status: '', saving: false };
			}
			return {
				sig: [
					ed.getEditedPostAttribute( 'title' ) || '',
					ed.getEditedPostAttribute( 'excerpt' ) || '',
					ed.getEditedPostContent() || ''
				].join( '' ),
				postType: ed.getCurrentPostType() || '',
				status: ed.getEditedPostAttribute( 'status' ) || '',
				saving: !! ( ed.isSavingPost && ed.isSavingPost() &&
					! ( ed.isAutosavingPost && ed.isAutosavingPost() ) )
			};
		}, [] );
		var currentHash = hashString( live.sig );

		var runCheck = useCallback( function ( force ) {
			var ed = wp.data.select( 'core/editor' );
			if ( ! ed ) {
				return;
			}
			// Never scan mid-save — the content is in flux.
			if ( ( ed.isSavingPost && ed.isSavingPost() ) ||
				( ed.isAutosavingPost && ed.isAutosavingPost() ) ) {
				return;
			}
			if ( ctl.current.inFlight ) {
				return;
			}
			var title = ed.getEditedPostAttribute( 'title' ) || '';
			var excerpt = ed.getEditedPostAttribute( 'excerpt' ) || '';
			var content = ed.getEditedPostContent() || '';
			var h = hashString( [ title, excerpt, content ].join( '' ) );
			if ( ! force && '' !== ctl.current.lastHash && ctl.current.lastHash === h ) {
				return;
			}
			ctl.current.inFlight = true;
			var myId = ++ctl.current.reqId;
			setSt( function ( s ) {
				return Object.assign( {}, s, { status: 'checking', error: '' } );
			} );

			var body = new URLSearchParams();
			body.set( 'action', 'rpca_editor_compliance_check' );
			body.set( 'nonce', cfg.nonce || '' );
			body.set( 'post_id', String( ed.getCurrentPostId() || 0 ) );
			body.set( 'post_type', ed.getCurrentPostType() || '' );
			body.set( 'title', title );
			body.set( 'excerpt', excerpt );
			body.set( 'content', content );

			fetch( cfg.ajaxUrl, {
				method: 'POST',
				credentials: 'same-origin',
				headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
				body: body.toString()
			} ).then( function ( r ) {
				return r.json().catch( function () { return null; } );
			} ).then( function ( j ) {
				// Always release the in-flight lock for the request that
				// owns it, THEN ignore a response a newer check superseded.
				ctl.current.inFlight = false;
				if ( myId !== ctl.current.reqId ) {
					return;
				}
				if ( j && j.success && j.data ) {
					ctl.current.lastHash = h;
					setSt( { status: 'done', result: j.data, checkedHash: h, error: '' } );
				} else {
					var msg = ( j && j.data && j.data.message ) ?
						j.data.message : 'The compliance check could not finish.';
					setSt( function ( s ) {
						return Object.assign( {}, s, { status: 'error', error: msg } );
					} );
				}
			} ).catch( function () {
				ctl.current.inFlight = false;
				if ( myId !== ctl.current.reqId ) {
					return;
				}
				setSt( function ( s ) {
					return Object.assign( {}, s, {
						status: 'error',
						error: 'The compliance check could not finish. Please try again.'
					} );
				} );
			} );
		}, [] );

		// Auto-check once when the panel first mounts.
		useEffect( function () {
			runCheck( false );
		}, [] );

		// Re-check after a real (non-autosave) save completes.
		useEffect( function () {
			if ( prevSaving.current && ! live.saving ) {
				runCheck( true );
			}
			prevSaving.current = live.saving;
		}, [ live.saving ] );

		// Belt-and-suspenders — the panel only applies to gated post types.
		if ( ! ELIGIBLE[ live.postType ] ) {
			return null;
		}

		var checking = 'checking' === st.status || 'idle' === st.status;
		var stale = '' !== st.checkedHash && st.checkedHash !== currentHash;
		var children = [];

		if ( 'error' === st.status ) {
			children.push( el( Notice, {
				key: 'err', status: 'error', isDismissible: false
			}, st.error || 'The compliance check could not finish.' ) );
		} else if ( checking ) {
			children.push( el( 'p', { key: 'checking', className: 'rpca-cc-line' },
				Spinner ? el( Spinner, {} ) : null, ' Checking this post…' ) );
		} else if ( 'done' === st.status && st.result ) {
			var v = verdict( st.result, live.status );
			children.push( el( Notice, {
				key: 'verdict', status: v.status, isDismissible: false
			}, v.text ) );

			if ( ! st.result.empty ) {
				var c = st.result.counts || {};
				children.push( el( 'p', {
					key: 'counts',
					style: { fontSize: '12px', color: '#475569', margin: '8px 0 4px' }
				}, 'Critical ' + ( c.critical || 0 ) + '  ·  High ' + ( c.high || 0 ) +
					'  ·  Medium ' + ( c.medium || 0 ) + '  ·  Low ' + ( c.low || 0 ) ) );

				var rows = st.result.findings || [];
				if ( rows.length ) {
					children.push( el( 'ul', {
						key: 'list',
						style: { margin: '4px 0 0', paddingLeft: '0', listStyle: 'none' }
					}, rows.map( function ( f, i ) {
						var m = sevMeta( f.severity );
						return el( 'li', {
							key: i,
							style: { margin: '0 0 8px', fontSize: '12px', lineHeight: '1.45' }
						},
							el( 'strong', { style: { color: m.color } }, m.label + ': ' ),
							el( 'span', {}, f.rule || 'Compliance finding' ),
							f.reason ? el( 'div', {
								style: { color: '#64748b', marginTop: '2px' }
							}, f.reason ) : null
						);
					} ) ) );
					if ( st.result.total > rows.length ) {
						children.push( el( 'p', {
							key: 'more',
							style: { fontSize: '11px', color: '#64748b', margin: '6px 0 0' }
						}, '…and ' + ( st.result.total - rows.length ) +
							' more. Open Compliance Guard for the full list.' ) );
					}
				}
			}
		}

		// Last-checked / staleness line.
		if ( 'done' === st.status && st.result ) {
			var info;
			if ( stale ) {
				info = 'Content changed since the last check — run it again.';
			} else {
				var when = '';
				if ( st.result.checkedAt ) {
					try {
						when = new Date( st.result.checkedAt * 1000 ).toLocaleTimeString();
					} catch ( e ) {
						when = '';
					}
				}
				info = when ? ( 'Checked at ' + when + '.' ) : 'Check complete.';
			}
			children.push( el( 'p', {
				key: 'info',
				style: { fontSize: '11px', color: '#64748b', margin: '10px 0 6px' }
			}, info ) );
		}

		children.push( el( Button, {
			key: 'btn',
			variant: 'secondary',
			isSecondary: true,
			disabled: checking && 'idle' !== st.status,
			onClick: function () { runCheck( true ); }
		}, checking && 'idle' !== st.status ? 'Checking…' : 'Check compliance' ) );

		return el( Panel, {
			name: 'rpca-compliance-check-panel',
			title: 'Compliance check',
			className: 'rpca-cc-panel',
			icon: 'shield'
		}, el( Fragment, {}, children ) );
	}

	registerPlugin( 'rpca-compliance-check', { render: ComplianceCheckPanel } );
} )( window.wp );
