/**
 * Encypher editor image-block provenance hints.
 *
 * For core media blocks whose attachment already carries source C2PA
 * provenance (or was signed with Encypher), add an Encypher action to the
 * selected block toolbar. The action opens the asset's provenance in place.
 * Data comes from attachment REST meta exposed read-only for editors. The
 * core data store supplies it when available. A same-origin media REST read
 * covers WordPress builds that do not resolve attachment entities in the editor.
 */
(function () {
    'use strict';

    if (!window.wp || !wp.hooks || !wp.element || !wp.compose || !wp.blockEditor || !wp.components || !wp.data) {
        return;
    }

    var el = wp.element.createElement;
    var Fragment = wp.element.Fragment;
    var useState = wp.element.useState;
    var useEffect = wp.element.useEffect;
    var createHigherOrderComponent = wp.compose.createHigherOrderComponent;
    var addFilter = wp.hooks.addFilter;
    var BlockControls = wp.blockEditor.BlockControls;
    var ToolbarGroup = wp.components.ToolbarGroup;
    var ToolbarButton = wp.components.ToolbarButton;
    var Modal = wp.components.Modal;
    var Notice = wp.components.Notice;
    var Button = wp.components.Button;
    var Spinner = wp.components.Spinner;
    var useSelect = wp.data.useSelect;
    var brandConfig = window.EncypherProvenanceConfig || {};

    var MEDIA_BLOCKS = ['core/image', 'core/audio', 'core/video', 'core/cover', 'core/media-text', 'core/gallery'];
    var SIGNED_STATUSES = ['signed', 'verified', 'c2pa_protected', 'c2pa_verified'];

    function parseMeta(value) {
        if (value && typeof value === 'object') {
            return value;
        }
        if (typeof value !== 'string' || !value) {
            return null;
        }
        try {
            var parsed = JSON.parse(value);
            return parsed && typeof parsed === 'object' ? parsed : null;
        } catch (e) {
            return null;
        }
    }

    function attachmentIdFor(props) {
        var attrs = props.attributes || {};
        if (props.name === 'core/media-text') {
            return attrs.mediaId || 0;
        }
        return attrs.id || 0;
    }

    function attachmentIdsFor(props, select) {
        if (props.name !== 'core/gallery') {
            var single = attachmentIdFor(props);
            return single ? [single] : [];
        }

        var attrs = props.attributes || {};
        var ids = Array.isArray(attrs.ids) ? attrs.ids.slice() : [];
        var blockEditor = select && select('core/block-editor');
        var gallery = blockEditor && blockEditor.getBlock && props.clientId
            ? blockEditor.getBlock(props.clientId)
            : null;
        function collect(blocks) {
            (blocks || []).forEach(function (block) {
                if (block && block.name === 'core/image' && block.attributes && block.attributes.id) {
                    ids.push(block.attributes.id);
                }
                if (block && block.innerBlocks) {
                    collect(block.innerBlocks);
                }
            });
        }
        if (gallery && gallery.innerBlocks) {
            collect(gallery.innerBlocks);
        }
        return ids.map(Number).filter(function (id, index, all) {
            return id > 0 && all.indexOf(id) === index;
        });
    }

    function summaryFor(meta) {
        return meta ? parseMeta(meta._encypher_source_c2pa_summary) : null;
    }

    function rightsFor(meta) {
        return meta ? parseMeta(meta._encypher_source_c2pa_rights) : null;
    }

    function noteFor(meta) {
        if (!meta) {
            return null;
        }
        if (meta._encypher_source_has_c2pa) {
            var summary = summaryFor(meta);
            if (summary && summary.statement) {
                return summary.statement;
            }
            var signer = meta._encypher_source_c2pa_signer || '';
            return signer
                ? 'Carries C2PA provenance from ' + signer
                : 'Carries C2PA provenance';
        }
        if (SIGNED_STATUSES.indexOf(meta._encypher_provenance_status) !== -1) {
            return 'Signed with Encypher';
        }
        return null;
    }

    function sourceFactRows(meta) {
        var summary = summaryFor(meta) || {};
        var rows = [];
        if (summary.software_agent) {
            rows.push('Created with: ' + summary.software_agent);
        }
        var format = String(summary.format || meta._encypher_source_c2pa_format || '').trim();
        if (format) {
            rows.push('Format: ' + format);
        }
        if (summary.signer || meta._encypher_source_c2pa_signer) {
            rows.push('Signed by: ' + (summary.signer || meta._encypher_source_c2pa_signer));
        }
        if (summary.source_type) {
            rows.push('Source: ' + summary.source_type);
        }
        if (typeof summary.valid === 'boolean') {
            rows.push(summary.valid
                ? 'Trust: signature and asset binding verified'
                : 'Trust: signature could not be verified');
        }
        if (summary.signed_at) {
            rows.push('Signed: ' + summary.signed_at);
        }
        return rows;
    }

    function sourceRightsRows(meta) {
        var rights = rightsFor(meta);
        if (!rights) {
            return [];
        }
        var embedded = rights.embedded || {};
        var embeddedRights = embedded.rights || {};
        var display = embeddedRights.display || {};
        var training = (embedded.training_mining || {}).use || {};
        var rows = ['Rights: preserved from the source asset'];
        var license = rights.license_type || embeddedRights.license_type;
        var usage = rights.usage_terms || display.usage_terms || embeddedRights.usage_terms;
        var licenseUrl = rights.license_url || display.license_url || embeddedRights.license_url;
        if (license) {
            rows.push('License: ' + license);
        }
        if (usage) {
            rows.push('Usage: ' + usage);
        } else if (licenseUrl) {
            rows.push('License terms: ' + licenseUrl);
        }
        [
            ['ai_training', 'AI training'],
            ['ai_inference', 'AI inference'],
            ['data_mining', 'Data mining'],
        ].forEach(function (item) {
            if (Object.prototype.hasOwnProperty.call(training, item[0])) {
                rows.push(item[1] + ': ' + (training[item[0]] ? 'allowed' : 'not allowed'));
            }
        });
        rows.push('These source rights are preserved when Encypher signs the post.');
        return rows;
    }

    function ProvenanceDetails(props) {
        var state = useState(null);
        var details = state[0];
        var setDetails = state[1];
        var loadingState = useState(false);
        var loading = loadingState[0];
        var setLoading = loadingState[1];
        var errorState = useState('');
        var error = errorState[0];
        var setError = errorState[1];

        function loadDetails() {
            if (details || loading) {
                return;
            }
            setLoading(true);
            setError('');
            wp.apiFetch({
                path: '/encypher-provenance/v1/media-provenance?attachment_id=' + props.id,
            }).then(function (response) {
                setDetails(response && response.details ? response.details : response);
            }).catch(function () {
                setError('Full C2PA information could not be loaded.');
            }).finally(function () {
                setLoading(false);
            });
        }

        var factRows = sourceFactRows(props.meta);
        var rightsRows = sourceRightsRows(props.meta);
        return el(
            'div',
            {
                className: 'encypher-media-hint-panel',
            },
            el(Notice, { status: 'info', isDismissible: false }, props.note),
            factRows.concat(rightsRows).map(function (row, index) {
                return el('p', { key: 'fact-' + index }, row);
            }),
            props.meta._encypher_source_has_c2pa
                ? el(
                    Fragment,
                    null,
                    el(Button, { variant: 'link', onClick: loadDetails, disabled: loading }, 'View full C2PA info'),
                    loading ? el(Spinner) : null,
                    error ? el(Notice, { status: 'error', isDismissible: false }, error) : null,
                    details ? el('pre', {
                        className: 'encypher-media-hint-panel__details',
                        style: { whiteSpace: 'pre-wrap', overflowWrap: 'anywhere', maxHeight: '360px', overflow: 'auto' },
                    }, JSON.stringify(details, null, 2)) : null
                )
                : null
        );
    }

    function displayPropsFor(props, sourceUrl) {
        var urlAttribute = {
            'core/image': 'url',
            'core/audio': 'src',
            'core/video': 'src',
            'core/cover': 'url',
            'core/media-text': 'mediaUrl',
        }[props.name];
        if (!urlAttribute || !sourceUrl || !props.attributes || props.attributes[urlAttribute] === sourceUrl) {
            return props;
        }
        var attributes = Object.assign({}, props.attributes);
        attributes[urlAttribute] = sourceUrl;
        return Object.assign({}, props, { attributes: attributes });
    }

    var withProvenanceHint = createHigherOrderComponent(function (BlockEdit) {
        return function (props) {
            if (MEDIA_BLOCKS.indexOf(props.name) === -1) {
                return el(BlockEdit, props);
            }
            var id = attachmentIdFor(props);
            var mediaRecord = useSelect(function (select) {
                if (!id) {
                    return null;
                }
                var core = select('core');
                return core && core.getEntityRecord
                    ? core.getEntityRecord('postType', 'attachment', id)
                    : null;
            }, [id]);
            var galleryRecords = useSelect(function (select) {
                if (props.name !== 'core/gallery') {
                    return [];
                }
                var ids = attachmentIdsFor(props, select);
                var core = select('core');
                return ids.map(function (attachmentId) {
                    return core && core.getEntityRecord
                        ? core.getEntityRecord('postType', 'attachment', attachmentId)
                        : null;
                }).filter(Boolean);
            }, [props.clientId, JSON.stringify((props.attributes || {}).ids || [])]);
            var fallbackState = useState(null);
            var fallbackRecord = fallbackState[0];
            var setFallbackRecord = fallbackState[1];
            var dialogState = useState(false);
            var dialogOpen = dialogState[0];
            var setDialogOpen = dialogState[1];
            useEffect(function () {
                var meta = mediaRecord && mediaRecord.meta ? mediaRecord.meta : null;
                if (!props.isSelected || !id || noteFor(meta)) {
                    return undefined;
                }
                var active = true;
                wp.apiFetch({
                    path: '/wp/v2/media/' + encodeURIComponent(id) + '?context=edit',
                }).then(function (record) {
                    if (active) {
                        setFallbackRecord(record || null);
                    }
                }).catch(function () {
                    // The editor keeps working without the optional provenance hint.
                });
                return function () {
                    active = false;
                };
            }, [id, props.isSelected]);

            var mediaMeta = mediaRecord && mediaRecord.meta ? mediaRecord.meta : null;
            var effectiveRecord = noteFor(mediaMeta) ? mediaRecord : fallbackRecord;
            var effectiveMeta = effectiveRecord && effectiveRecord.meta ? effectiveRecord.meta : null;
            var note = noteFor(effectiveMeta);
            var galleryProvenance = Array.isArray(galleryRecords)
                ? galleryRecords.filter(function (record) { return noteFor(record && record.meta); })
                : [];
            if (props.name === 'core/gallery') {
                note = galleryProvenance.length
                    ? galleryProvenance.length + (galleryProvenance.length === 1
                        ? ' gallery image carries provenance'
                        : ' gallery images carry provenance')
                    : null;
            }
            var displayProps = note
                ? displayPropsFor(props, effectiveRecord && effectiveRecord.source_url)
                : props;

            return el(
                Fragment,
                null,
                el(BlockEdit, displayProps),
                props.isSelected && note
                    ? el(
                        Fragment,
                        null,
                        el(
                            BlockControls,
                            { group: 'other' },
                            el(
                                ToolbarGroup,
                                null,
                                el(ToolbarButton, {
                                    icon: brandConfig.markUrl
                                        ? el('img', {
                                            src: brandConfig.markUrl,
                                            alt: '',
                                            'aria-hidden': 'true',
                                            width: 20,
                                            height: 20,
                                        })
                                        : 'info-outline',
                                    label: 'View Encypher provenance',
                                    onClick: function () { setDialogOpen(true); },
                                })
                            )
                        ),
                        dialogOpen
                            ? el(
                                Modal,
                                {
                                    title: 'Encypher Provenance',
                                    onRequestClose: function () { setDialogOpen(false); },
                                    className: 'encypher-media-hint-modal',
                                },
                                props.name === 'core/gallery'
                                    ? el(
                                        'div',
                                        { className: 'encypher-media-hint-gallery' },
                                        galleryProvenance.map(function (record) {
                                            return el(ProvenanceDetails, {
                                                key: record.id,
                                                id: record.id,
                                                meta: record.meta,
                                                note: noteFor(record.meta),
                                            });
                                        })
                                    )
                                    : el(ProvenanceDetails, { id: id, meta: effectiveMeta, note: note })
                            )
                            : null
                    )
                    : null
            );
        };
    }, 'withEncypherProvenanceHint');

    addFilter('editor.BlockEdit', 'encypher-provenance/media-provenance-hint', withProvenanceHint, 9);

    // Exposed for contract testing; these are pure mappings.
    window.EncypherMediaHints = {
        noteFor: noteFor,
        attachmentIdFor: attachmentIdFor,
        attachmentIdsFor: attachmentIdsFor,
        summaryFor: summaryFor,
        rightsFor: rightsFor,
        sourceFactRows: sourceFactRows,
        displayPropsFor: displayPropsFor,
        sourceRightsRows: sourceRightsRows,
    };
})();
