(function () {
    'use strict';

    const { registerPlugin } = wp.plugins;
    const PluginDocumentSettingPanel =
        (wp.editor && wp.editor.PluginDocumentSettingPanel) ||
        (wp.editPost && wp.editPost.PluginDocumentSettingPanel);
    const PluginSidebar =
        (wp.editor && wp.editor.PluginSidebar) ||
        (wp.editPost && wp.editPost.PluginSidebar);
    const PluginPrePublishPanel =
        (wp.editor && wp.editor.PluginPrePublishPanel) ||
        (wp.editPost && wp.editPost.PluginPrePublishPanel);
    const { Button, Notice, SelectControl, TextControl, TextareaControl, ToggleControl } = wp.components;
    const { useState, useEffect, useRef, createPortal } = wp.element;
    const { useSelect, useDispatch } = wp.data;
    const apiFetch = wp.apiFetch;

    const PROVENANCE_STATES = ['not_signed', 'signing', 'signed', 'verified', 'edited', 'needs_attention'];
    const ASSURANCE_STATES = ['unknown', 'held', 'live_unverified', 'live_verified', 'failed', 'cancelled', 'superseded'];
    const SIGNING_NOTICE_ID = 'encypher-signing-progress';
    const OUTCOME_NOTICE_ID = 'encypher-publication-outcome';
    const POLL_INTERVAL = 3000;
    const MIN_VERIFY_VISIBLE_MS = 900;
    const SIDEBAR_NAME = 'encypher';
    const SIDEBAR_SELECTOR = 'encypher-provenance-sidebar/' + SIDEBAR_NAME;
    const BLOCK_TYPES = [
        'core/paragraph', 'core/heading', 'core/list', 'core/quote', 'core/image',
        'core/audio', 'core/video', 'core/gallery', 'core/cover', 'core/media-text'
    ];
    const BLOCK_COPY = {
        covered: ['Covered by current provenance', 'Unchanged from the latest signed generation.'],
        edited: ['Not covered by current provenance', 'Changed since signing. Sign again to include this version.'],
        ingredient: ['Third-party provenance ingredient', 'Encypher preserves this media source provenance when signing.'],
        unsigned: ['Not covered: document is unsigned', 'Publish or sign to add document provenance.'],
        unknown: ['Coverage unknown', 'Encypher cannot compare this block with the latest signed generation.']
    };
    const EDITORIAL_FIELDS = [
        { key: '_encypher_public_provenance_note', label: 'Public provenance note', help: 'A public statement about production steps.', limit: 500, textarea: true },
        { key: '_encypher_credit_line', label: 'Credit line', help: 'Credit for the person or organization that supplied the item.', limit: 255 },
        { key: '_encypher_source', label: 'Source or supplier', help: 'Name the person or party in the content supply chain.', limit: 255 },
        { key: '_encypher_transmission_reference', label: 'Receiver reference', help: 'The job reference assigned by the receiving organization.', limit: 120 }
    ];
    const SOURCE_OPTIONS = [
        { value: '', label: 'Not declared' },
        { value: 'human_created', label: 'Human created' },
        { value: 'generative_ai_edited', label: 'Edited with generative AI' },
        { value: 'generative_ai_created', label: 'Created with generative AI' }
    ];

    function exactState(value, values, fallback) {
        return values.indexOf(value) !== -1 ? value : fallback;
    }

    function normalizeStatus(response) {
        const source = response && typeof response === 'object' ? response : {};
        const assurance = source.assurance && typeof source.assurance === 'object' ? source.assurance : {};
        const chainProjection = source.chain && typeof source.chain === 'object' && !Array.isArray(source.chain)
            ? source.chain
            : (assurance.chain && typeof assurance.chain === 'object' ? assurance.chain : {});
        const chain = Array.isArray(source.chain)
            ? source.chain
            : (Array.isArray(chainProjection.entries) ? chainProjection.entries : []);
        const failure = source.failure && typeof source.failure === 'object'
            ? source.failure
            : (assurance.failure && typeof assurance.failure === 'object'
                ? assurance.failure
                : (source.last_sign_error && typeof source.last_sign_error === 'object' ? source.last_sign_error : null));
        const legacyState = {
            c2pa_protected: 'signed',
            c2pa_verified: 'verified',
            modified: 'edited',
            verification_failed: 'needs_attention',
            embedding_failed: 'needs_attention',
            media_signing_failed: 'needs_attention'
        }[source.status] || source.status;
        return {
            provenance_state: exactState(source.provenance_state || legacyState, PROVENANCE_STATES, 'not_signed'),
            assurance_state: exactState(source.assurance_state, ASSURANCE_STATES, 'unknown'),
            display_state: exactState(source.display_state || legacyState, PROVENANCE_STATES, 'not_signed'),
            raw_status: typeof source.status === 'string' ? source.status : '',
            internal_state: String(assurance.internal_state || source.internal_state || ''),
            severity: String(assurance.severity || source.severity || 'none'),
            last_signed: typeof source.last_signed === 'string' ? source.last_signed : '',
            failure: failure,
            sign_errors: Array.isArray(source.sign_errors) ? source.sign_errors : [],
            receipt: source.receipt && typeof source.receipt === 'object'
                ? source.receipt
                : (assurance.receipt && typeof assurance.receipt === 'object' ? assurance.receipt : {}),
            registry: source.registry && typeof source.registry === 'object'
                ? source.registry
                : (assurance.registry && typeof assurance.registry === 'object' ? assurance.registry : {}),
            chain: chain,
            actions: source.actions && typeof source.actions === 'object'
                ? source.actions
                : (assurance.actions && typeof assurance.actions === 'object' ? assurance.actions : {}),
            publication_generation: String(source.publication_generation || assurance.publication_generation || ''),
            publish_facts: source.publish_facts && typeof source.publish_facts === 'object'
                ? source.publish_facts
                : (assurance.publish_facts && typeof assurance.publish_facts === 'object' ? assurance.publish_facts : {}),
            connection: source.connection && typeof source.connection === 'object' ? source.connection : {}
        };
    }

    function publishPhase(facts) {
        const publishFacts = facts.publish_facts || {};
        if (facts.severity === 'bypassed' || facts.internal_state === 'emergency_unsigned') {
            return 'blocked';
        }
        if (publishFacts.fail_open === true) {
            return 'fail_open';
        }
        if (facts.assurance_state === 'held') {
            return 'held';
        }
        if (facts.assurance_state === 'live_verified') {
            return 'signed_live';
        }
        if (facts.assurance_state === 'failed' || facts.display_state === 'needs_attention') {
            return 'blocked';
        }
        return 'will_sign';
    }

    function statusPresentation(facts, isPublished) {
        const emergencyBypass = facts.severity === 'bypassed' || facts.internal_state === 'emergency_unsigned';
        if (emergencyBypass) {
            return ['error', 'Emergency unsigned publication', 'This generation bypassed protection through the audited emergency control.'];
        }
        if (facts.assurance_state === 'cancelled') {
            return ['pending', 'Held publication cancelled', 'The cancelled candidate will not be released.'];
        }
        if (facts.assurance_state === 'superseded') {
            return ['pending', 'Superseded', 'A newer publication generation replaced this one.'];
        }
        if (publishPhase(facts) === 'fail_open') {
            return facts.display_state === 'needs_attention'
                ? ['error', 'Signing failed; post is live', facts.failure && facts.failure.message
                    ? facts.failure.message + ' WordPress published this generation under fail-open policy.'
                    : 'WordPress published this generation under fail-open policy without Encypher protection.']
                : ['pending', 'Fail-open publishing', 'WordPress can publish without waiting for Encypher protection.'];
        }
        if (facts.assurance_state === 'held') {
            return ['signing', 'Held for signing', 'The candidate is not public. Encypher will release this exact generation after signing succeeds.'];
        }
        if (facts.assurance_state === 'live_verified') {
            return ['verified', 'Signed and live', 'The signed generation is public and its live provenance check passed.'];
        }
        if (facts.assurance_state === 'failed') {
            return ['error', 'Protection failed', facts.failure && facts.failure.message ? facts.failure.message : 'The candidate remains blocked. Retry signing or cancel it.'];
        }
        if (facts.display_state === 'signing') {
            return ['signing', 'Queued', 'Encypher is signing this generation. This panel will update at the terminal state.'];
        }
        if (facts.display_state === 'needs_attention') {
            return ['error', 'Signing failed', facts.failure && facts.failure.message ? facts.failure.message : 'Retry signing to protect the current generation.'];
        }
        if (facts.display_state === 'signed' || facts.display_state === 'verified') {
            return [facts.display_state === 'verified' ? 'verified' : 'signed', facts.assurance_state === 'live_unverified' ? 'Signed, checking live page' : 'Signed', facts.assurance_state === 'live_unverified' ? 'Encypher is checking the public page.' : 'The current generation carries signed provenance.'];
        }
        if (facts.display_state === 'edited') {
            return ['pending', 'Edited since signing', 'These changes are not covered by the last signature.'];
        }
        return ['pending', isPublished ? 'Sign now' : 'Will sign', isPublished ? 'This public generation is not protected.' : 'Publishing will send this exact generation to Encypher for signing.'];
    }

    function shouldPoll(facts) {
        return facts.provenance_state === 'signing'
            || facts.display_state === 'signing'
            || facts.assurance_state === 'held'
            || facts.assurance_state === 'live_unverified';
    }

    function sourceLabel(value) {
        const match = SOURCE_OPTIONS.find(function (option) { return option.value === value; });
        return match ? match.label : SOURCE_OPTIONS[0].label;
    }

    function prePublishRows(facts, license, source, media) {
        const policy = facts.publish_facts || {};
        const connected = typeof policy.connected === 'boolean'
            ? policy.connected
            : (typeof facts.connection.connected === 'boolean' ? facts.connection.connected : null);
        const policyKnown = typeof policy.protected_publish_enabled === 'boolean' || policy.fail_open === true;
        const protectedMode = policy.protected_publish_enabled !== false && policy.fail_open !== true;
        return [
            { key: 'policy', label: 'Protection policy', value: !policyKnown ? 'Checking' : (protectedMode ? (policy.applies === false ? 'Protected mode does not apply to this post' : 'Protected mode applies') : 'Fail open') },
            { key: 'connection', label: 'Encypher connection', value: connected === true ? 'Connected' : (connected === false ? 'Not connected' : 'Checking') },
            { key: 'candidate', label: 'Candidate', value: policy.candidate_status || facts.provenance_state.replace(/_/g, ' ') },
            { key: 'license', label: 'Selected license', value: license || 'Site default' },
            { key: 'source', label: 'Source / AI declaration', value: source || 'Not declared' },
            { key: 'media', label: 'Media readiness', value: policy.media_summary || media || (policy.media_ready === true ? 'Ready' : (policy.media_ready === false ? 'Needs attention' : 'Checking')) },
            { key: 'release', label: 'On publish', value: !policyKnown ? 'Checking protection policy' : (protectedMode ? 'Hold until this generation is signed' : 'Publish immediately if signing is unavailable') }
        ];
    }

    function chainRows(chain) {
        return (Array.isArray(chain) ? chain : []).map(function (entry, index) {
            const item = entry && typeof entry === 'object' ? entry : {};
            return {
                key: item.sequence || item.generation || String(index),
                generation: String(item.generation || ''),
                event: String(item.type || 'signed_generation'),
                action: String(item.type || 'Signed generation').replace(/_/g, ' '),
                detail: item.reason || item.at || '',
                dashboard_url: item.dashboard_url || ''
            };
        });
    }

    window.EncypherEditorUX = {
        normalizeStatus: normalizeStatus,
        publishPhase: publishPhase,
        statusPresentation: statusPresentation,
        shouldPoll: shouldPoll,
        prePublishRows: prePublishRows,
        chainRows: chainRows,
        metadataFields: EDITORIAL_FIELDS.slice(),
        digitalSourceOptions: SOURCE_OPTIONS.slice()
    };

    function findBlockPath(blocks, clientId, parentPath) {
        const path = parentPath || [];
        for (let index = 0; index < (blocks || []).length; index++) {
            const block = blocks[index];
            const next = path.concat(index);
            if (block && block.clientId === clientId) return next;
            const nested = block && block.innerBlocks && block.innerBlocks.length ? findBlockPath(block.innerBlocks, clientId, next) : null;
            if (nested) return nested;
        }
        return null;
    }

    function blockAtPath(blocks, path) {
        let list = blocks || [];
        let block = null;
        for (let index = 0; path && index < path.length; index++) {
            block = list[path[index]] || null;
            if (!block) return null;
            list = block.innerBlocks || [];
        }
        return block;
    }

    function findBlockById(blocks, id) {
        for (let index = 0; index < (blocks || []).length; index++) {
            const block = blocks[index];
            if (block && block.attributes && block.attributes.encypherBlockId === id) return block;
            const nested = block && block.innerBlocks && block.innerBlocks.length ? findBlockById(block.innerBlocks, id) : null;
            if (nested) return nested;
        }
        return null;
    }

    function comparableBlock(block) {
        if (!block) return null;
        const attributes = Object.assign({}, block.attributes || {});
        delete attributes.encypherBlockId;
        return Object.assign({}, block, { attributes: attributes, innerBlocks: (block.innerBlocks || []).map(comparableBlock) });
    }

    function serializedBlock(block) {
        if (!block || !wp.blocks || typeof wp.blocks.serialize !== 'function') return null;
        try { return wp.blocks.serialize([comparableBlock(block)]); } catch (error) { return null; }
    }

    function savedBlock(selected, current, saved) {
        if (!selected) return null;
        const id = selected.attributes && selected.attributes.encypherBlockId;
        const matched = id ? findBlockById(saved, id) : null;
        if (matched) return matched;
        const path = findBlockPath(current, selected.clientId, []);
        return path ? blockAtPath(saved, path) : null;
    }

    function attachmentIds(block) {
        if (!block) return [];
        const attrs = block.attributes || {};
        let ids = block.name === 'core/gallery' && Array.isArray(attrs.ids)
            ? attrs.ids.filter(Boolean)
            : (block.name === 'core/media-text' ? (attrs.mediaId ? [attrs.mediaId] : []) : (attrs.id ? [attrs.id] : []));
        (block.innerBlocks || []).forEach(function (inner) { ids = ids.concat(attachmentIds(inner)); });
        return ids.filter(function (id, index) { return ids.indexOf(id) === index; });
    }

    function parseBlocks(content) {
        if (typeof content !== 'string' || !wp.blocks || typeof wp.blocks.parse !== 'function') return [];
        try { return wp.blocks.parse(content) || []; } catch (error) { return []; }
    }

    function blockState(input) {
        const selected = input.selectedBlock;
        if (!selected) return null;
        if (BLOCK_TYPES.indexOf(selected.name) === -1) return 'unknown';
        const documentStatus = {
            c2pa_protected: 'signed',
            c2pa_verified: 'verified',
            modified: 'edited'
        }[input.documentStatus] || input.documentStatus;
        if (documentStatus === 'not_signed') return 'unsigned';
        if (input.hasThirdPartyProvenance) return 'ingredient';
        if (['signed', 'verified', 'edited'].indexOf(documentStatus) === -1) return 'unknown';
        const oldBlock = savedBlock(selected, input.currentBlocks || [], input.savedBlocks || input.persistedBlocks || []);
        const currentText = serializedBlock(selected);
        const oldText = serializedBlock(oldBlock);
        if (!oldBlock || !currentText || !oldText) return 'unknown';
        return currentText === oldText ? 'covered' : 'edited';
    }

    window.EncypherBlockProvenance = { resolve: blockState, supportedTypes: BLOCK_TYPES.slice() };

    function logo(variant, loading) {
        const config = window.EncypherProvenanceConfig || {};
        return wp.element.createElement('img', { className: 'encypher-logo encypher-logo--' + variant, src: loading ? (config.loaderUrl || '') : (config.markUrl || ''), alt: '', 'aria-hidden': 'true' });
    }

    function openSidebar(section) {
        const dispatcher = wp.data.dispatch ? wp.data.dispatch('core/edit-post') : null;
        if (dispatcher && typeof dispatcher.openGeneralSidebar === 'function') dispatcher.openGeneralSidebar(SIDEBAR_SELECTOR);
        window.setTimeout(function () {
            const target = document.getElementById('encypher-sidebar-' + (section || 'outcome'));
            if (target && typeof target.scrollIntoView === 'function') {
                target.scrollIntoView({ block: 'start', behavior: 'smooth' });
                if (typeof target.focus === 'function') target.focus({ preventScroll: true });
            }
        }, 0);
    }

    window.EncypherEditorSidebar = { open: openSidebar, selector: SIDEBAR_SELECTOR };

    const HeaderChip = function (props) {
        const [mount, setMount] = useState(null);
        useEffect(function () {
            const findMount = function () {
                const target = document.querySelector('.editor-header__settings') || document.querySelector('.edit-post-header__settings') || document.querySelector('.edit-post-header__toolbar');
                if (!target) return;
                let root = document.getElementById('encypher-header-chip-root');
                if (!root) {
                    root = document.createElement('div');
                    root.id = 'encypher-header-chip-root';
                    root.className = 'encypher-header-chip-root';
                    target.insertBefore(root, target.firstChild);
                }
                setMount(root);
            };
            findMount();
            const observer = typeof MutationObserver === 'function' ? new MutationObserver(findMount) : null;
            if (observer) observer.observe(document.body, { childList: true, subtree: true });
            return function () {
                if (observer) observer.disconnect();
                const root = document.getElementById('encypher-header-chip-root');
                if (root && root.parentNode && typeof root.parentNode.removeChild === 'function') root.parentNode.removeChild(root);
            };
        }, []);
        if (!mount) return null;
        const copy = statusPresentation(props.facts, props.isPublished);
        const modifier = copy[0] === 'verified' || copy[0] === 'signed' ? 'signed' : (copy[0] === 'error' ? 'error' : (copy[0] === 'signing' ? 'progress' : 'pending'));
        return createPortal(wp.element.createElement('button', {
            type: 'button',
            className: 'encypher-header-chip encypher-header-chip--' + modifier,
            onClick: props.onOpen,
            title: 'Open Encypher protection details',
            'aria-label': 'Open Encypher protection details: ' + copy[1],
            'data-encypher-provenance-state': props.facts.provenance_state,
            'data-encypher-assurance-state': props.facts.assurance_state,
            'data-encypher-display-state': props.facts.display_state,
            'data-encypher-publish-phase': publishPhase(props.facts)
        }, logo('header', props.facts.display_state === 'signing'), wp.element.createElement('span', { className: 'encypher-header-chip__label', role: 'status', 'aria-live': 'polite' }, copy[1])), mount);
    };

    const StatusPanel = function () {
        const editor = useSelect(function (select) {
            const store = select('core/editor');
            const post = typeof store.getCurrentPost === 'function' ? store.getCurrentPost() : null;
            return {
                postId: store.getCurrentPostId(),
                status: store.getEditedPostAttribute('status'),
                meta: store.getEditedPostAttribute('meta') || {},
                isSaving: store.isSavingPost(),
                isAutosaving: typeof store.isAutosavingPost === 'function' ? store.isAutosavingPost() : false,
                saveSucceeded: typeof store.didPostSaveRequestSucceed === 'function' ? store.didPostSaveRequestSucceed() : true,
                saveFailed: typeof store.didPostSaveRequestFail === 'function' ? store.didPostSaveRequestFail() : false,
                savedContent: post && typeof post.content === 'string' ? post.content : (post && post.content && post.content.raw ? post.content.raw : '')
            };
        }, []);
        const selectedBlock = useSelect(function (select) {
            const store = select('core/block-editor');
            return store && typeof store.getSelectedBlock === 'function' ? store.getSelectedBlock() : null;
        }, []);
        const currentBlocks = useSelect(function (select) {
            const store = select('core/block-editor');
            return store && typeof store.getBlocks === 'function' ? store.getBlocks() : [];
        }, []);
        const mediaSnapshot = useSelect(function (select) {
            const core = select('core');
            const ids = [];
            const walk = function (blocks) {
                (blocks || []).forEach(function (block) {
                    attachmentIds(block).forEach(function (id) { if (ids.indexOf(id) === -1) ids.push(id); });
                    walk(block.innerBlocks || []);
                });
            };
            walk(currentBlocks);
            if (!ids.length) return { summary: 'No media to sign', selectedThirdParty: false };
            if (!core || typeof core.getEntityRecord !== 'function') return { summary: 'Checking ' + ids.length + ' media item' + (ids.length === 1 ? '' : 's'), selectedThirdParty: false };
            const records = ids.map(function (id) { return core.getEntityRecord('postType', 'attachment', id); });
            const ready = records.filter(Boolean).length;
            return {
                summary: ready === ids.length ? ids.length + ' media item' + (ids.length === 1 ? '' : 's') + ' ready' : 'Checking media (' + ready + ' of ' + ids.length + ' ready)',
                selectedThirdParty: attachmentIds(selectedBlock).some(function (id) {
                    const record = core.getEntityRecord('postType', 'attachment', id);
                    return Boolean(record && record.meta && record.meta._encypher_source_has_c2pa);
                })
            };
        }, [selectedBlock, currentBlocks]);

        const [facts, setFacts] = useState(normalizeStatus({}));
        const [loading, setLoading] = useState(true);
        const [verifying, setVerifying] = useState(false);
        const [retrying, setRetrying] = useState(false);
        const [canceling, setCanceling] = useState(false);
        const [verifyUnavailable, setVerifyUnavailable] = useState(false);
        const [catalogState, setCatalogState] = useState(window.EncypherLicenseCatalog && window.EncypherLicenseCatalog.state ? window.EncypherLicenseCatalog.state() : null);
        const [rightsTemplate, setRightsTemplate] = useState('');
        const [rightsCustom, setRightsCustom] = useState({});
        const pollRef = useRef(null);
        const wasSavingRef = useRef(false);
        const saveAutosaveRef = useRef(false);
        const savePublishRef = useRef(false);
        const announcedRef = useRef('');
        const { editPost } = useDispatch('core/editor');
        const editorUi = useDispatch('core/edit-post') || {};
        const notices = useDispatch('core/notices') || {};
        const info = notices.createInfoNotice || function () {};
        const success = notices.createSuccessNotice || function () {};
        const errorNotice = notices.createErrorNotice || function () {};
        const removeNotice = notices.removeNotice || function () {};
        const postId = editor.postId;

        const stopPolling = function () {
            if (pollRef.current) clearInterval(pollRef.current);
            pollRef.current = null;
        };
        const announce = function (next) {
            const phase = publishPhase(next);
            if (shouldPoll(next) || announcedRef.current === phase) return;
            announcedRef.current = phase;
            removeNotice(SIGNING_NOTICE_ID);
            removeNotice(OUTCOME_NOTICE_ID);
            const options = { id: OUTCOME_NOTICE_ID, isDismissible: false };
            if (phase === 'signed_live') success('Signed and live. Encypher verified the public generation.', options);
            if (phase === 'blocked') errorNotice(next.failure && next.failure.message ? next.failure.message : 'Protection failed. The candidate remains blocked.', options);
            if (phase === 'fail_open' && next.display_state === 'needs_attention') {
                errorNotice(
                    next.failure && next.failure.message
                        ? next.failure.message + ' The post is live under fail-open policy.'
                        : 'Signing failed. The post is live under fail-open policy.',
                    options
                );
            }
            if (next.assurance_state === 'cancelled') info('Held publication cancelled. The candidate will not be released.', options);
        };
        let fetchStatus;
        const startPolling = function () {
            if (pollRef.current) return;
            removeNotice(SIGNING_NOTICE_ID);
            info('Queued for Encypher signing...', { id: SIGNING_NOTICE_ID, type: 'snackbar', isDismissible: false });
            pollRef.current = setInterval(function () { fetchStatus(true); }, POLL_INTERVAL);
        };
        fetchStatus = function (silent) {
            if (!postId) return Promise.resolve(null);
            if (!silent) setLoading(true);
            return apiFetch({ path: 'encypher-provenance/v1/status?post_id=' + postId, method: 'GET', headers: { 'X-WP-Nonce': (window.EncypherProvenanceConfig || {}).nonce || '' } }).then(function (response) {
                const next = normalizeStatus(response);
                setFacts(next);
                setLoading(false);
                if (shouldPoll(next)) startPolling(); else { stopPolling(); announce(next); }
                return next;
            }).catch(function () { if (!silent) setLoading(false); return null; });
        };

        useEffect(function () {
            fetchStatus();
            if (window.EncypherLicenseCatalog && window.EncypherLicenseCatalog.load) window.EncypherLicenseCatalog.load().then(setCatalogState).catch(function () {});
            return stopPolling;
        }, [postId]);
        useEffect(function () {
            const value = editor.meta._encypher_rights || '';
            if (!value) { setRightsTemplate(''); setRightsCustom({}); return; }
            try {
                const parsed = typeof value === 'string' ? JSON.parse(value) : value;
                setRightsTemplate(parsed.template || '');
                setRightsCustom(parsed.custom || {});
            } catch (error) { setRightsTemplate(''); setRightsCustom({}); }
        }, [editor.meta._encypher_rights]);
        useEffect(function () {
            const visible = function () { if (document.visibilityState === 'visible') fetchStatus(true); };
            document.addEventListener('visibilitychange', visible);
            return function () { document.removeEventListener('visibilitychange', visible); };
        }, [postId]);
        useEffect(function () {
            if (!wasSavingRef.current && editor.isSaving) {
                saveAutosaveRef.current = editor.isAutosaving;
                savePublishRef.current = editor.status === 'publish';
                if (savePublishRef.current && !editor.isAutosaving) {
                    setFacts(Object.assign({}, facts, { provenance_state: 'signing', assurance_state: facts.publish_facts.fail_open === true ? 'unknown' : 'held', display_state: 'signing' }));
                    announcedRef.current = '';
                    if (typeof editorUi.closePublishSidebar === 'function') editorUi.closePublishSidebar();
                    startPolling();
                }
            }
            if (wasSavingRef.current && !editor.isSaving) {
                const run = savePublishRef.current && postId && !saveAutosaveRef.current && !editor.isAutosaving && editor.saveSucceeded && !editor.saveFailed;
                saveAutosaveRef.current = false;
                savePublishRef.current = false;
                if (run) {
                    apiFetch({ path: 'encypher-provenance/v1/run-pending', method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': (window.EncypherProvenanceConfig || {}).nonce || '' }, data: { post_id: postId } }).then(function () {
                        window.setTimeout(function () { fetchStatus(true); }, 500);
                    }).catch(function (error) {
                        stopPolling();
                        removeNotice(SIGNING_NOTICE_ID);
                        errorNotice(error && error.message ? error.message : 'Signing could not start.', { id: OUTCOME_NOTICE_ID, isDismissible: false });
                        fetchStatus(true);
                    });
                }
            }
            wasSavingRef.current = editor.isSaving;
        }, [editor.isSaving, editor.isAutosaving, editor.saveSucceeded, editor.saveFailed, editor.status, postId]);

        const isPublished = editor.status === 'publish';
        const copy = statusPresentation(facts, isPublished);
        const phase = publishPhase(facts);
        const oldBlocks = parseBlocks(editor.savedContent);
        const selectedState = blockState({ selectedBlock: selectedBlock, currentBlocks: currentBlocks, savedBlocks: oldBlocks, documentStatus: facts.raw_status || facts.provenance_state, hasThirdPartyProvenance: mediaSnapshot.selectedThirdParty });
        const selectedCopy = selectedState ? BLOCK_COPY[selectedState] : null;

        const verify = function () {
            if (!postId || verifying || ['signed', 'verified'].indexOf(facts.provenance_state) === -1) return;
            setVerifying(true);
            setVerifyUnavailable(false);
            const started = Date.now();
            apiFetch({ path: 'encypher-provenance/v1/verify', method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': (window.EncypherProvenanceConfig || {}).nonce || '' }, data: { post_id: postId } }).then(function (response) {
                window.setTimeout(function () {
                    setFacts(Object.assign({}, facts, { provenance_state: response && response.valid ? 'verified' : 'needs_attention', display_state: response && response.valid ? 'verified' : 'needs_attention' }));
                    setVerifying(false);
                    fetchStatus(true);
                }, Math.max(0, MIN_VERIFY_VISIBLE_MS - (Date.now() - started)));
            }).catch(function () {
                window.setTimeout(function () { setVerifyUnavailable(true); setVerifying(false); }, Math.max(0, MIN_VERIFY_VISIBLE_MS - (Date.now() - started)));
            });
        };
        const retry = function () {
            if (!postId || retrying || facts.actions.can_retry === false) return;
            setRetrying(true);
            setFacts(Object.assign({}, facts, { provenance_state: 'signing', display_state: 'signing', failure: null }));
            announcedRef.current = '';
            apiFetch({ path: 'encypher-provenance/v1/retry', method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': (window.EncypherProvenanceConfig || {}).nonce || '' }, data: { post_id: postId } }).then(function () {
                setRetrying(false); startPolling(); fetchStatus(true);
            }).catch(function (error) {
                const failure = { message: error && error.message ? error.message : 'Retry failed.' };
                setFacts(Object.assign({}, facts, { provenance_state: 'needs_attention', display_state: 'needs_attention', failure: failure }));
                setRetrying(false); stopPolling(); errorNotice(failure.message, { id: OUTCOME_NOTICE_ID, isDismissible: false });
            });
        };
        const cancel = function () {
            const protectedCandidate = facts.publish_facts.protected_publish_enabled !== false && facts.publish_facts.fail_open !== true;
            if (!postId || canceling || !protectedCandidate || facts.actions.can_cancel !== true || !facts.publication_generation) return;
            if (typeof window.confirm === 'function' && !window.confirm('Cancel this held publication? The candidate will not be published.')) return;
            setCanceling(true);
            apiFetch({ path: 'encypher-provenance/v1/publication/cancel', method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': (window.EncypherProvenanceConfig || {}).nonce || '' }, data: { post_id: postId, generation: facts.publication_generation } }).then(function () {
                setCanceling(false); stopPolling(); fetchStatus(true);
            }).catch(function (error) {
                setCanceling(false); errorNotice(error && error.message ? error.message : 'Held publication could not be cancelled.', { id: OUTCOME_NOTICE_ID, isDismissible: false });
            });
        };

        const licenseOptions = window.EncypherLicenseCatalog && window.EncypherLicenseCatalog.comboboxOptions
            ? window.EncypherLicenseCatalog.comboboxOptions(false, rightsTemplate)
            : [{ value: '', label: 'Use site default' }];
        const selectedLicense = licenseOptions.find(function (option) { return option.value === rightsTemplate; });
        const licenseLabel = selectedLicense ? selectedLicense.label : (rightsTemplate || 'Site default');
        let editorialRecord = { schema_version: 1, include_in_provenance: false };
        try {
            const storedEditorialRecord = JSON.parse(String(editor.meta._encypher_editorial_metadata || ''));
            if (storedEditorialRecord && typeof storedEditorialRecord === 'object' && Number(storedEditorialRecord.schema_version || 1) === 1) {
                editorialRecord = Object.assign({}, storedEditorialRecord, {
                    schema_version: 1,
                    include_in_provenance: storedEditorialRecord.include_in_provenance === true
                });
            }
        } catch (metadataError) {
            editorialRecord = { schema_version: 1, include_in_provenance: false };
        }
        const includeEditorialMetadata = editorialRecord.include_in_provenance === true;
        const selectedSourceDeclaration = sourceLabel(String(editor.meta._encypher_digital_source_type || ''));
        const sourceDeclaration = includeEditorialMetadata
            ? selectedSourceDeclaration
            : selectedSourceDeclaration + ' (not included in public provenance)';

        const prePublish = function () {
            if (!PluginPrePublishPanel || !postId) return null;
            return wp.element.createElement(PluginPrePublishPanel, { name: 'encypher-protection-preview', title: 'Encypher protection', className: 'encypher-prepublish-panel', initialOpen: true },
                wp.element.createElement('section', {
                    className: 'encypher-prepublish',
                    'data-encypher-provenance-state': facts.provenance_state,
                    'data-encypher-assurance-state': facts.assurance_state,
                    'data-encypher-display-state': facts.display_state,
                    'data-encypher-publish-phase': phase,
                    'aria-busy': loading ? 'true' : 'false'
                },
                wp.element.createElement('p', { className: 'encypher-prepublish__summary' }, loading ? 'Checking Encypher protection policy...' : (phase === 'fail_open' ? 'This post can publish before signing completes.' : 'This post will be held until Encypher signs the exact candidate.')),
                wp.element.createElement('dl', { className: 'encypher-fact-list' }, prePublishRows(facts, licenseLabel, sourceDeclaration, mediaSnapshot.summary).map(function (row) {
                    return wp.element.createElement('div', { key: row.key, className: 'encypher-fact-list__row', 'data-encypher-prepublish-fact': row.key }, wp.element.createElement('dt', null, row.label), wp.element.createElement('dd', null, row.value));
                }))));
        };

        const editorialControls = function () {
            const inclusionControl = wp.element.createElement(ToggleControl, {
                key: 'include-in-provenance',
                label: 'Include editorial metadata in C2PA manifest',
                help: includeEditorialMetadata
                    ? 'On: Encypher will sign these fields, making them public.'
                    : 'Off: WordPress stores these fields, but Encypher will not sign or publish them.',
                checked: includeEditorialMetadata,
                onChange: function (checked) {
                    editPost({
                        meta: {
                            _encypher_editorial_metadata: JSON.stringify(Object.assign({}, editorialRecord, {
                                schema_version: 1,
                                include_in_provenance: checked === true
                            }))
                        }
                    });
                }
            });
            const children = EDITORIAL_FIELDS.map(function (field) {
                const value = String(editor.meta[field.key] || '');
                const Control = field.textarea ? TextareaControl : TextControl;
                return wp.element.createElement('div', { key: field.key, className: 'encypher-editorial-field' },
                    wp.element.createElement(Control, { label: field.label, help: field.help, value: value, rows: field.textarea ? 3 : undefined, onChange: function (nextValue) {
                        const patch = {}; patch[field.key] = Array.from(String(nextValue || '')).slice(0, field.limit).join(''); editPost({ meta: patch });
                    } }),
                    wp.element.createElement('span', { className: 'encypher-character-count', 'aria-live': 'polite' }, Math.max(0, field.limit - Array.from(value).length) + ' characters remaining'));
            });
            children.push(wp.element.createElement(SelectControl, { key: 'source-type', label: 'Source / AI declaration', help: includeEditorialMetadata ? 'Encypher will sign this declaration into public provenance.' : 'Stored in WordPress only until editorial metadata inclusion is turned on.', value: String(editor.meta._encypher_digital_source_type || ''), options: SOURCE_OPTIONS, onChange: function (value) { editPost({ meta: { _encypher_digital_source_type: value || '' } }); } }));
            return wp.element.createElement('details', { id: 'encypher-sidebar-metadata', className: 'encypher-editorial-provenance' }, wp.element.createElement('summary', null, 'Public provenance metadata'), wp.element.createElement('div', { className: 'encypher-editorial-provenance__body' }, inclusionControl, wp.element.createElement('p', { className: 'description encypher-editorial-warning' }, includeEditorialMetadata ? 'These fields will become public when signed. Do not include confidential notes or source contact details.' : 'These fields remain in WordPress and will not be included in public provenance.'), children));
        };

        const rightsControls = function () {
            const children = [wp.element.createElement(SelectControl, { key: 'license', label: 'Document license', help: 'This is the license Encypher will sign for the document.', value: rightsTemplate, options: licenseOptions, onChange: function (value) {
                const nextCustom = value === 'custom' ? rightsCustom : {};
                setRightsTemplate(value || ''); setRightsCustom(nextCustom); editPost({ meta: { _encypher_rights: JSON.stringify(value ? { template: value, custom: value === 'custom' ? nextCustom : undefined } : {}) } });
            } })];
            if (catalogState && catalogState.available === false) children.push(wp.element.createElement(Notice, { key: 'warning', status: 'warning', isDismissible: false }, 'License templates are unavailable. The saved selection remains in effect.'));
            const preview = window.EncypherLicenseCatalog && window.EncypherLicenseCatalog.previewRows ? window.EncypherLicenseCatalog.previewRows(rightsTemplate) : [];
            if (preview.length) children.push(wp.element.createElement('dl', { key: 'preview', className: 'encypher-rights-preview' }, preview.map(function (row) { return wp.element.createElement('div', { key: row.label }, wp.element.createElement('dt', null, row.label), wp.element.createElement('dd', null, row.value)); })));
            children.push(wp.element.createElement('p', { key: 'dashboard', className: 'encypher-rights-dashboard-link' }, wp.element.createElement('a', { href: 'https://dashboard.encypher.com/rights', target: '_blank', rel: 'noopener noreferrer' }, 'Manage license templates in your Encypher dashboard')));
            return wp.element.createElement('details', { id: 'encypher-sidebar-rights', className: 'encypher-document-rights' }, wp.element.createElement('summary', null, 'License and AI use'), wp.element.createElement('div', { className: 'encypher-document-rights__body' }, children));
        };

        const registryAndChain = function () {
            const receipt = facts.receipt || {};
            const registry = facts.registry || {};
            const rows = chainRows(facts.chain);
            const receiptStatus = receipt.integrity || receipt.availability || (receipt.url ? 'recorded' : 'pending');
            return wp.element.createElement('section', { id: 'encypher-sidebar-registry', className: 'encypher-registry-chain' },
                wp.element.createElement('h3', null, 'Registry receipt and edit chain'),
                wp.element.createElement('dl', { className: 'encypher-fact-list' },
                    wp.element.createElement('div', { className: 'encypher-fact-list__row' }, wp.element.createElement('dt', null, 'Registry receipt'), wp.element.createElement('dd', { 'data-encypher-receipt-state': receiptStatus }, String(receiptStatus).replace(/_/g, ' '))),
                    wp.element.createElement('div', { className: 'encypher-fact-list__row' }, wp.element.createElement('dt', null, 'Registry delivery'), wp.element.createElement('dd', null, String(registry.delivery_state || 'not queued').replace(/_/g, ' ')))),
                receipt.url ? wp.element.createElement('a', { className: 'encypher-receipt-link', href: receipt.url, target: '_blank', rel: 'noopener noreferrer' }, 'View registry receipt') : null,
                registry.dashboard_url ? wp.element.createElement('a', { className: 'encypher-registry-dashboard-link', href: registry.dashboard_url, target: '_blank', rel: 'noopener noreferrer' }, 'Open registry record') : null,
                wp.element.createElement('ol', { className: 'encypher-publication-chain', 'data-encypher-chain-length': rows.length }, rows.map(function (row) {
                    return wp.element.createElement('li', { key: row.key, 'data-encypher-generation': row.generation, 'data-encypher-chain-event': row.event }, wp.element.createElement('strong', null, row.action), row.detail ? wp.element.createElement('span', null, row.detail) : null);
                })),
                !rows.length ? wp.element.createElement('p', { className: 'description' }, 'No signed generations yet.') : null);
        };

        const actionButtons = [];
        const canRetrySigning = facts.actions.can_retry === true
            || (typeof facts.actions.can_retry !== 'boolean'
                && (facts.display_state === 'needs_attention' || facts.display_state === 'edited'));
        if (['signed', 'verified'].indexOf(facts.provenance_state) !== -1) actionButtons.push(wp.element.createElement(Button, { key: 'verify', variant: 'secondary', onClick: verify, disabled: verifying }, verifying ? 'Verifying...' : 'Verify signed provenance'));
        if (facts.display_state === 'not_signed' && isPublished && facts.actions.can_retry !== false) actionButtons.push(wp.element.createElement(Button, { key: 'sign', className: 'encypher-retry-signing', 'data-post-id': postId, variant: 'primary', onClick: retry, disabled: retrying }, retrying ? 'Queued' : 'Sign now'));
        if (canRetrySigning) actionButtons.push(wp.element.createElement(Button, { key: 'retry', className: 'encypher-retry-signing', 'data-post-id': postId, variant: 'primary', onClick: retry, disabled: retrying }, retrying ? 'Queued' : 'Retry failed signing'));
        const protectedCandidate = facts.publish_facts.protected_publish_enabled !== false && facts.publish_facts.fail_open !== true;
        if (protectedCandidate && (facts.assurance_state === 'held' || facts.assurance_state === 'failed') && facts.actions.can_cancel === true) actionButtons.push(wp.element.createElement(Button, { key: 'cancel', className: 'encypher-cancel-held-publication', 'data-post-id': postId, variant: 'secondary', isDestructive: true, onClick: cancel, disabled: canceling }, canceling ? 'Cancelling...' : 'Cancel held publication'));

        const sidebarBody = wp.element.createElement('div', { className: 'encypher-provenance-status encypher-sidebar-shell' },
            wp.element.createElement('section', { id: 'encypher-sidebar-outcome', className: 'encypher-publication-outcome', tabIndex: '-1', 'data-encypher-provenance-state': facts.provenance_state, 'data-encypher-assurance-state': facts.assurance_state, 'data-encypher-display-state': facts.display_state, 'data-encypher-publish-phase': phase },
                wp.element.createElement('div', { className: 'encypher-status-hero encypher-status-hero--' + copy[0], role: 'status', 'aria-live': 'polite' }, wp.element.createElement('div', { className: 'encypher-hero-icon' }, logo('hero', facts.display_state === 'signing')), wp.element.createElement('div', { className: 'encypher-hero-body' }, wp.element.createElement('div', { className: 'encypher-hero-headline' }, loading ? 'Checking protection...' : copy[1]), wp.element.createElement('div', { className: 'encypher-hero-sub' }, copy[2]))),
                wp.element.createElement('dl', { className: 'encypher-current-declarations', 'aria-label': 'Current provenance declarations' },
                    wp.element.createElement('div', null,
                        wp.element.createElement('dt', null, 'License'),
                        wp.element.createElement('dd', null, licenseLabel)),
                    wp.element.createElement('div', null,
                        wp.element.createElement('dt', null, 'Source / AI'),
                        wp.element.createElement('dd', null, sourceDeclaration))),
                verifyUnavailable ? wp.element.createElement('p', { className: 'encypher-verify-unavailable', role: 'status' }, 'Verification unavailable. Try again.') : null,
                facts.last_signed && ['signed', 'verified'].indexOf(facts.provenance_state) !== -1 ? wp.element.createElement('p', { className: 'encypher-signed-time' }, 'Signed ' + facts.last_signed) : null,
                facts.sign_errors.length ? wp.element.createElement(Notice, { status: 'warning', isDismissible: false }, facts.sign_errors.length + ' media item' + (facts.sign_errors.length === 1 ? '' : 's') + ' need attention.') : null,
                actionButtons.length ? wp.element.createElement('div', { className: 'encypher-editor-actions' }, actionButtons) : null),
            selectedCopy ? wp.element.createElement('div', { className: 'encypher-block-provenance-status encypher-block-provenance-status--' + selectedState, 'data-state': selectedState, role: 'status' }, wp.element.createElement('strong', null, selectedCopy[0]), wp.element.createElement('span', null, selectedCopy[1])) : null,
            registryAndChain(), editorialControls(), rightsControls(),
            wp.element.createElement('a', { className: 'components-button is-secondary encypher-dashboard-button', href: 'https://dashboard.encypher.com/', target: '_blank', rel: 'noopener noreferrer' }, 'Open Encypher dashboard'));

        const sidebar = PluginSidebar
            ? wp.element.createElement(PluginSidebar, { name: SIDEBAR_NAME, title: 'Encypher', className: 'encypher-provenance-sidebar', icon: logo('sidebar', false), isPinnable: false }, sidebarBody)
            : wp.element.createElement(PluginDocumentSettingPanel, { name: 'encypher-provenance-panel', title: 'Encypher', className: 'encypher-provenance-panel' }, sidebarBody);
        return wp.element.createElement(wp.element.Fragment, null,
            wp.element.createElement(HeaderChip, { facts: facts, isPublished: isPublished, onOpen: function () { openSidebar('outcome'); } }),
            prePublish(), sidebar);
    };

    registerPlugin('encypher-provenance-sidebar', {
        render: function () { return wp.element.createElement(StatusPanel); },
        icon: wp.element.createElement('img', { src: (window.EncypherProvenanceConfig || {}).markUrl || '', alt: '', 'aria-hidden': 'true', width: 20, height: 20 })
    });
}());
