(function () {
    'use strict';

    var POLL_INTERVAL_MS = 3000;
    var POLL_TIMEOUT_MS = 300000;
    var active = [];
    var brandConfig = window.EncypherProvenanceConfig || {};

    function classify(response) {
        response = response || {};
        if (response.status === 'signing') {
            return 'signing';
        }
        if (response.error || response.status === 'needs_attention' || response.status === 'error') {
            return 'needs_attention';
        }
        if (response.status === 'signed' || response.status === 'verified') {
            return 'signed';
        }
        return 'not_signed';
    }

    function errorMessage(response) {
        if (!response || !response.error) {
            return '';
        }
        if (typeof response.error === 'string') {
            return response.error;
        }
        return typeof response.error.message === 'string' ? response.error.message : '';
    }

    function prependStatusIcon(node, state) {
        var doc = node && node.ownerDocument;
        if (!doc || typeof doc.createElement !== 'function' || typeof node.insertBefore !== 'function') {
            return;
        }
        var icon = doc.createElement('img');
        icon.className = 'encypher-status-icon';
        icon.src = state === 'signing' ? (brandConfig.loaderUrl || '') : (brandConfig.markUrl || '');
        icon.alt = '';
        icon.width = 16;
        icon.height = 16;
        icon.style.verticalAlign = 'text-bottom';
        icon.setAttribute('aria-hidden', 'true');
        node.insertBefore(doc.createTextNode(' '), node.firstChild);
        node.insertBefore(icon, node.firstChild);
    }

    function render(node, response) {
        var state = classify(response);
        var labels = {
            signing: 'Signing',
            signed: 'Signed by you',
            needs_attention: 'Needs attention',
            not_signed: 'Not signed'
        };
        var message = errorMessage(response);

        node.setAttribute('data-status', state);
        node.textContent = labels[state] + (state === 'needs_attention' && message ? ': ' + message : '');
        prependStatusIcon(node, state);
        return state;
    }

    function stop(node) {
        for (var index = active.length - 1; index >= 0; index -= 1) {
            var record = active[index];
            if (!node || record.node === node) {
                if (record.timer !== null) {
                    window.clearInterval(record.timer);
                }
                active.splice(index, 1);
            }
        }
    }

    function statusPath(node) {
        return 'encypher-provenance/v1/media-status?attachment_id=' + encodeURIComponent(node.getAttribute('data-attachment-id') || '');
    }

    function start(node) {
        if (!node || !window.wp || !wp.apiFetch) {
            return null;
        }

        stop(node);
        var record = {
            node: node,
            startedAt: Date.now(),
            timer: null,
            inFlight: false
        };
        active.push(record);

        function settle(response) {
            record.inFlight = false;
            var state = render(node, response);
            if (state !== 'signing') {
                stop(node);
            }
            return state;
        }

        function fail(error) {
            var message = error && error.message
                ? error.message
                : 'Could not check media signing status. Retry signing this attachment.';
            return settle({ status: 'needs_attention', error: { message: message } });
        }

        function check() {
            if (Date.now() - record.startedAt >= POLL_TIMEOUT_MS) {
                settle({
                    status: 'needs_attention',
                    error: { message: 'Media signing did not complete within five minutes. Retry signing this attachment.' }
                });
                return null;
            }
            if (record.inFlight) {
                return null;
            }
            record.inFlight = true;
            return wp.apiFetch({ path: statusPath(node), method: 'GET' }).then(settle, fail);
        }

        var first = check();
        if (first && typeof first.then === 'function') {
            return first.then(function (state) {
                if (state === 'signing' && active.indexOf(record) !== -1 && record.timer === null) {
                    record.timer = window.setInterval(check, POLL_INTERVAL_MS);
                }
                return record;
            });
        }
        return record;
    }

    function retryPurge(button, statusNode) {
        if (!button || !window.wp || !wp.apiFetch) {
            return Promise.reject(new Error('Public delivery retry is unavailable.'));
        }
        var attachmentId = button.getAttribute('data-attachment-id') || '';
        if (!/^\d+$/.test(attachmentId)) {
            return Promise.reject(new Error('Attachment ID is missing.'));
        }

        button.disabled = true;
        button.setAttribute('aria-disabled', 'true');
        button.setAttribute('aria-busy', 'true');
        button.textContent = 'Retrying public delivery...';

        return wp.apiFetch({
            path: 'encypher-provenance/v1/media-purge',
            method: 'POST',
            data: { attachment_id: Number(attachmentId) }
        }).then(function (response) {
            button.removeAttribute('aria-busy');
            button.textContent = 'Public delivery restored';
            if (statusNode) {
                render(statusNode, response);
            }
            return response;
        }, function (error) {
            button.disabled = false;
            button.removeAttribute('aria-disabled');
            button.removeAttribute('aria-busy');
            button.textContent = 'Retry public delivery';
            throw error;
        });
    }

    function init() {
        var nodes = document.querySelectorAll('[data-encypher-media-status][data-attachment-id]');
        for (var index = 0; index < nodes.length; index += 1) {
            if (nodes[index].getAttribute('data-status') === 'signing') {
                start(nodes[index]);
            }
        }
        var retryNodes = document.querySelectorAll('[data-encypher-purge-retry][data-attachment-id]');
        for (var retryIndex = 0; retryIndex < retryNodes.length; retryIndex += 1) {
            retryNodes[retryIndex].addEventListener('click', function (event) {
                event.preventDefault();
                var attachmentId = this.getAttribute('data-attachment-id') || '';
                var selector = '[data-encypher-media-status][data-attachment-id="' + attachmentId.replace(/\D/g, '') + '"]';
                var statusNode = typeof document.querySelector === 'function' ? document.querySelector(selector) : null;
                retryPurge(this, statusNode).catch(function () {});
            });
        }
    }

    window.EncypherMediaSigningStatus = {
        POLL_INTERVAL_MS: POLL_INTERVAL_MS,
        POLL_TIMEOUT_MS: POLL_TIMEOUT_MS,
        classify: classify,
        render: render,
        start: start,
        stop: stop,
        retryPurge: retryPurge
    };

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();
