import { Assertions, Chain, GeneralSteps, Logger, NamedChain, Pipeline, Step, UiFinder } from '@ephox/agar';
import { UnitTest } from '@ephox/bedrock-client';
import { Arr, Fun, Result } from '@ephox/katamari';
import { Attribute, Compare, Html, Insert, SelectorFilter, SugarElement, Truncate } from '@ephox/sugar';
import * as DescribedHandler from 'ephox/alloy/events/DescribedHandler';
import { EventRegistry } from 'ephox/alloy/events/EventRegistry';
import * as Tagger from 'ephox/alloy/registry/Tagger';
UnitTest.asynctest('EventRegistryTest', (success, failure) => {
    const body = SugarElement.fromDom(document.body);
    const page = SugarElement.fromTag('div');
    Html.set(page, '<div data-test-uid="comp-1">' +
        '<div data-test-uid="comp-2">' +
        '<div data-test-uid="comp-3">' +
        '<div data-test-uid="comp-4">' +
        '<div data-test-uid="comp-5"></div>' +
        '</div>' +
        '</div>' +
        '</div>' +
        '</div>');
    // Add alloy UID tags to match these attributes.
    const pageBits = SelectorFilter.descendants(page, '[data-test-uid]');
    Arr.each(pageBits, (bit) => {
        Attribute.getOpt(bit, 'data-test-uid').each((testUid) => Tagger.writeOnly(bit, testUid));
    });
    const isRoot = Fun.curry(Compare.eq, page);
    Insert.append(body, page);
    const events = EventRegistry();
    events.registerId(['extra-args'], 'comp-1', {
        'event.alpha': DescribedHandler.uncurried((extra) => 'event.alpha.1(' + extra + ')', 'event.alpha.1.handler'),
        'event.only': DescribedHandler.uncurried((extra) => 'event.only(' + extra + ')', 'event.only.handler')
    });
    events.registerId(['extra-args'], 'comp-4', {
        'event.alpha': DescribedHandler.uncurried((extra) => 'event.alpha.4(' + extra + ')', 'event.alpha.4.handler')
    });
    const sAssertFilterByType = (expected, type) => Step.sync(() => {
        const filtered = events.filterByType(type);
        const raw = Arr.map(filtered, (f) => ({
            // Invoke the handler
            handler: f.descHandler.cHandler(),
            purpose: f.descHandler.purpose,
            id: f.id
        })).sort((f, g) => {
            if (f.id < g.id) {
                return -1;
            }
            else if (f.id > g.id) {
                return +1;
            }
            else {
                return 0;
            }
        });
        Assertions.assertEq(() => 'filter(' + type + ') = ' + JSON.stringify(expected), expected, raw);
    });
    const sAssertNotFound = (label, type, id) => Logger.t('Test: ' + label + '\nLooking for handlers for  id = ' + id + ' and event = ' + type + '. Should not find any', GeneralSteps.sequence([
        Chain.asStep(page, [
            UiFinder.cFindIn('[data-test-uid="' + id + '"]'),
            Chain.binder((target) => {
                const handler = events.find(isRoot, type, target);
                return handler.fold(() => Result.value({}), (h) => Result.error('Unexpected handler found: ' + JSON.stringify({
                    element: Truncate.getHtml(h.element),
                    // INVESTIGATE: Should this have changed?
                    handler: h.descHandler
                })));
            })
        ])
    ]));
    const sAssertFind = (label, expected, type, id) => {
        const cFindHandler = Chain.binder((target) => events.find(isRoot, type, target).fold(() => Result.error('No event handler for ' + type + ' on ' + target.dom), Result.value));
        return Logger.t('Test: ' + label + '\nLooking for handlers for  id = ' + id + ' and event = ' + type, GeneralSteps.sequence([
            Chain.asStep({}, [
                NamedChain.asChain([
                    NamedChain.writeValue('page', page),
                    NamedChain.direct('page', UiFinder.cFindIn('[data-test-uid="' + id + '"]'), 'target'),
                    NamedChain.direct('target', cFindHandler, 'handler'),
                    NamedChain.bundle(Result.value)
                ]),
                Chain.op((actual) => {
                    const section = actual.handler;
                    Assertions.assertEq('find(' + type + ', ' + id + ') = true', expected.target, Attribute.get(section.element, 'data-test-uid'));
                    Assertions.assertEq(() => 'find(' + type + ', ' + id + ') = ' + JSON.stringify(expected.handler), expected.handler, section.descHandler.cHandler());
                })
            ])
        ]));
    };
    Pipeline.async({}, [
        sAssertFilterByType([], 'event.none'),
        sAssertFilterByType([
            { handler: 'event.alpha.1(extra-args)', id: 'comp-1', purpose: 'event.alpha.1.handler' },
            { handler: 'event.alpha.4(extra-args)', id: 'comp-4', purpose: 'event.alpha.4.handler' }
        ], 'event.alpha'),
        sAssertFind('comp-1!', { handler: 'event.alpha.1(extra-args)', target: 'comp-1', purpose: 'event.alpha.1.handler' }, 'event.alpha', 'comp-1'),
        sAssertFind('comp-2 > comp-1', { handler: 'event.alpha.1(extra-args)', target: 'comp-1' }, 'event.alpha', 'comp-2'),
        sAssertFind('comp-3 > comp-2 > comp-1', { handler: 'event.alpha.1(extra-args)', target: 'comp-1' }, 'event.alpha', 'comp-3'),
        sAssertFind('comp-4!', { handler: 'event.alpha.4(extra-args)', target: 'comp-4' }, 'event.alpha', 'comp-4'),
        sAssertFind('comp-5 > comp-4!', { handler: 'event.alpha.4(extra-args)', target: 'comp-4' }, 'event.alpha', 'comp-5'),
        sAssertNotFound('comp-5 > comp-4 > comp-3 > comp-2 > comp-1 > NOT FOUND', 'event.beta', 'comp-5'),
        sAssertFind('comp-5 > comp-4 > comp-3 > comp-2 > comp-1!', { handler: 'event.only(extra-args)', target: 'comp-1' }, 'event.only', 'comp-5')
    ], success, failure);
});
//# sourceMappingURL=EventRegistryTest.js.map