import * as d3 from 'd3';
import { t } from '../../util/locale';
import { modeBrowse, modeSelect } from '../../modes';
import { utilRebind } from '../../util/rebind';
import { icon, pointBox, transitionTime } from './helper';


export function uiIntroNavigation(context, reveal) {
    var dispatch = d3.dispatch('done'),
        timeouts = [],
        hallId = 'n2061',
        townHall = [-85.63591, 41.94285],
        springStreetId = 'w397',
        springStreetEndId = 'n1834',
        springStreet = [-85.63582, 41.94255],
        onewayField = context.presets().field('oneway'),
        maxspeedField = context.presets().field('maxspeed');


    var chapter = {
        title: 'intro.navigation.title'
    };


    function timeout(f, t) {
        timeouts.push(window.setTimeout(f, t));
    }


    function eventCancel() {
        d3.event.stopPropagation();
        d3.event.preventDefault();
    }


    function isTownHallSelected() {
        var ids = context.selectedIDs();
        return ids.length === 1 && ids[0] === hallId;
    }


    function dragMap() {
        context.enter(modeBrowse(context));
        context.history().reset('initial');

        var msec = transitionTime(townHall, context.map().center());
        if (msec) { reveal(null, null, { duration: 0 }); }
        context.map().zoom(19).centerEase(townHall, msec);

        timeout(function() {
            var centerStart = context.map().center();

            reveal('#surface', t('intro.navigation.drag'));
            context.map().on('drawn.intro', function() {
                reveal('#surface', t('intro.navigation.drag'), { duration: 0 });
            });

            context.map().on('move.intro', function() {
                var centerNow = context.map().center();
                if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
                    context.map().on('move.intro', null);
                    timeout(function() { continueTo(zoomMap); }, 3000);
                }
            });

        }, msec + 100);

        function continueTo(nextStep) {
            context.map().on('move.intro drawn.intro', null);
            nextStep();
        }
    }


    function zoomMap() {
        var zoomStart = context.map().zoom();

        reveal('#surface',
            t('intro.navigation.zoom', {
                plus: icon('#icon-plus', 'pre-text'),
                minus: icon('#icon-minus', 'pre-text')
            })
        );

        context.map().on('drawn.intro', function() {
            reveal('#surface',
                t('intro.navigation.zoom', {
                    plus: icon('#icon-plus', 'pre-text'),
                    minus: icon('#icon-minus', 'pre-text')
                }), { duration: 0 }
            );
        });

        context.map().on('move.intro', function() {
            if (context.map().zoom() !== zoomStart) {
                context.map().on('move.intro', null);
                timeout(function() { continueTo(features); }, 3000);
            }
        });

        function continueTo(nextStep) {
            context.map().on('move.intro drawn.intro', null);
            nextStep();
        }
    }


    function features() {
        var onClick = function() { continueTo(pointsLinesAreas); };

        reveal('#surface', t('intro.navigation.features'),
            { buttonText: t('intro.ok'), buttonCallback: onClick }
        );

        context.map().on('drawn.intro', function() {
            reveal('#surface', t('intro.navigation.features'),
                { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
            );
        });

        function continueTo(nextStep) {
            context.map().on('drawn.intro', null);
            nextStep();
        }
    }

    function pointsLinesAreas() {
        var onClick = function() { continueTo(nodesWays); };

        reveal('#surface', t('intro.navigation.points_lines_areas'),
            { buttonText: t('intro.ok'), buttonCallback: onClick }
        );

        context.map().on('drawn.intro', function() {
            reveal('#surface', t('intro.navigation.points_lines_areas'),
                { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
            );
        });

        function continueTo(nextStep) {
            context.map().on('drawn.intro', null);
            nextStep();
        }
    }

    function nodesWays() {
        var onClick = function() { continueTo(clickTownHall); };

        reveal('#surface', t('intro.navigation.nodes_ways'),
            { buttonText: t('intro.ok'), buttonCallback: onClick }
        );

        context.map().on('drawn.intro', function() {
            reveal('#surface', t('intro.navigation.nodes_ways'),
                { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
            );
        });

        function continueTo(nextStep) {
            context.map().on('drawn.intro', null);
            nextStep();
        }
    }

    function clickTownHall() {
        context.enter(modeBrowse(context));
        context.history().reset('initial');

        reveal(null, null, { duration: 0 });
        context.map().zoomEase(19, 500);

        timeout(function() {
            var entity = context.hasEntity(hallId);
            if (!entity) return;
            context.map().centerEase(entity.loc, 500);

            timeout(function() {
                var entity = context.hasEntity(hallId);
                if (!entity) return;
                var box = pointBox(entity.loc, context);
                reveal(box, t('intro.navigation.click_townhall'));

                context.map().on('move.intro drawn.intro', function() {
                    var entity = context.hasEntity(hallId);
                    if (!entity) return;
                    var box = pointBox(entity.loc, context);
                    reveal(box, t('intro.navigation.click_townhall'), { duration: 0 });
                });

                context.on('enter.intro', function() {
                    if (isTownHallSelected()) continueTo(selectedTownHall);
                });

            }, 550);  // after centerEase

        }, 550); // after zoomEase

        context.history().on('change.intro', function() {
            if (!context.hasEntity(hallId)) {
                continueTo(clickTownHall);
            }
        });

        function continueTo(nextStep) {
            context.on('enter.intro', null);
            context.map().on('move.intro drawn.intro', null);
            context.history().on('change.intro', null);
            nextStep();
        }
    }


    function selectedTownHall() {
        if (!isTownHallSelected()) return clickTownHall();

        var entity = context.hasEntity(hallId);
        if (!entity) return clickTownHall();

        var box = pointBox(entity.loc, context);
        var onClick = function() { continueTo(editorTownHall); };

        reveal(box, t('intro.navigation.selected_townhall'),
            { buttonText: t('intro.ok'), buttonCallback: onClick }
        );

        context.map().on('move.intro drawn.intro', function() {
            var entity = context.hasEntity(hallId);
            if (!entity) return;
            var box = pointBox(entity.loc, context);
            reveal(box, t('intro.navigation.selected_townhall'),
                { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
            );
        });

        context.history().on('change.intro', function() {
            if (!context.hasEntity(hallId)) {
                continueTo(clickTownHall);
            }
        });

        function continueTo(nextStep) {
            context.map().on('move.intro drawn.intro', null);
            context.history().on('change.intro', null);
            nextStep();
        }
    }


    function editorTownHall() {
        if (!isTownHallSelected()) return clickTownHall();

        // disallow scrolling
        d3.select('.inspector-wrap').on('wheel.intro', eventCancel);

        var onClick = function() { continueTo(presetTownHall); };

        reveal('.entity-editor-pane',
            t('intro.navigation.editor_townhall'),
            { buttonText: t('intro.ok'), buttonCallback: onClick }
        );

        context.on('exit.intro', function() {
            continueTo(clickTownHall);
        });

        context.history().on('change.intro', function() {
            if (!context.hasEntity(hallId)) {
                continueTo(clickTownHall);
            }
        });

        function continueTo(nextStep) {
            context.on('exit.intro', null);
            context.history().on('change.intro', null);
            d3.select('.inspector-wrap').on('wheel.intro', null);
            nextStep();
        }
    }


    function presetTownHall() {
        if (!isTownHallSelected()) return clickTownHall();

        // reset pane, in case user happened to change it..
        d3.select('.inspector-wrap .panewrap').style('right', '0%');
        // disallow scrolling
        d3.select('.inspector-wrap').on('wheel.intro', eventCancel);

        // preset match, in case the user happened to change it.
        var entity = context.entity(context.selectedIDs()[0]);
        var preset = context.presets().match(entity, context.graph());

        var onClick = function() { continueTo(fieldsTownHall); };

        context.on('exit.intro', function() {
            continueTo(clickTownHall);
        });

        context.history().on('change.intro', function() {
            if (!context.hasEntity(hallId)) {
                continueTo(clickTownHall);
            }
        });

        reveal('.inspector-body .preset-list-item.inspector-inner',
            t('intro.navigation.preset_townhall', { preset: preset.name() }),
            { buttonText: t('intro.ok'), buttonCallback: onClick }
        );

        function continueTo(nextStep) {
            context.on('exit.intro', null);
            context.history().on('change.intro', null);
            d3.select('.inspector-wrap').on('wheel.intro', null);
            nextStep();
        }
    }


    function fieldsTownHall() {
        if (!isTownHallSelected()) return clickTownHall();

        // reset pane, in case user happened to change it..
        d3.select('.inspector-wrap .panewrap').style('right', '0%');
        // disallow scrolling
        d3.select('.inspector-wrap').on('wheel.intro', eventCancel);

        var onClick = function() { continueTo(closeTownHall); };

        reveal('.inspector-body .preset-editor',
            t('intro.navigation.fields_townhall'),
            { buttonText: t('intro.ok'), buttonCallback: onClick }
        );

        context.on('exit.intro', function() {
            continueTo(clickTownHall);
        });

        context.history().on('change.intro', function() {
            if (!context.hasEntity(hallId)) {
                continueTo(clickTownHall);
            }
        });

        function continueTo(nextStep) {
            context.on('exit.intro', null);
            context.history().on('change.intro', null);
            d3.select('.inspector-wrap').on('wheel.intro', null);
            nextStep();
        }
    }


    function closeTownHall() {
        if (!isTownHallSelected()) return clickTownHall();

        var selector = '.entity-editor-pane button.preset-close svg use';
        var href = d3.select(selector).attr('href') || '#icon-close';

        reveal('.entity-editor-pane',
            t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') })
        );

        context.on('exit.intro', function() {
            continueTo(searchStreet);
        });

        context.history().on('change.intro', function() {
            // update the close icon in the tooltip if the user edits something.
            var selector = '.entity-editor-pane button.preset-close svg use';
            var href = d3.select(selector).attr('href') || '#icon-close';

            reveal('.entity-editor-pane',
                t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') }),
                { duration: 0 }
            );
        });

        function continueTo(nextStep) {
            context.on('exit.intro', null);
            context.history().on('change.intro', null);
            nextStep();
        }
    }


    function searchStreet() {
        context.enter(modeBrowse(context));
        context.history().reset('initial');  // ensure spring street exists

        var msec = transitionTime(springStreet, context.map().center());
        if (msec) { reveal(null, null, { duration: 0 }); }
        context.map().zoom(19).centerEase(springStreet, msec);  // ..and user can see it

        timeout(function() {
            reveal('.search-header input',
                t('intro.navigation.search_street', { name: t('intro.graph.name.spring-street') })
            );

            d3.select('.search-header input')
                .on('keyup.intro', checkSearchResult);
        }, msec + 100);
    }


    function checkSearchResult() {
        var first = d3.select('.feature-list-item:nth-child(0n+2)'),  // skip "No Results" item
            firstName = first.select('.entity-name'),
            name = t('intro.graph.name.spring-street');

        if (!firstName.empty() && firstName.text() === name) {
            reveal(first.node(),
                t('intro.navigation.choose_street', { name: name }),
                { duration: 300 }
            );

            context.on('exit.intro', function() {
                continueTo(selectedStreet);
            });

            d3.select('.search-header input')
                .on('keydown.intro', eventCancel, true)
                .on('keyup.intro', null);
        }

        function continueTo(nextStep) {
            context.on('exit.intro', null);
            d3.select('.search-header input')
                .on('keydown.intro', null)
                .on('keyup.intro', null);
            nextStep();
        }
    }


    function selectedStreet() {
        if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
            return searchStreet();
        }

        var onClick = function() { continueTo(editorStreet); };
        var entity = context.entity(springStreetEndId);
        var box = pointBox(entity.loc, context);
        box.height = 500;

        reveal(box,
            t('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
            { duration: 600, buttonText: t('intro.ok'), buttonCallback: onClick }
        );

        timeout(function() {
            context.map().on('move.intro drawn.intro', function() {
                var entity = context.hasEntity(springStreetEndId);
                if (!entity) return;
                var box = pointBox(entity.loc, context);
                box.height = 500;
                reveal(box,
                    t('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
                    { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
                );
            });
        }, 600);  // after reveal.

        context.on('enter.intro', function(mode) {
            if (!context.hasEntity(springStreetId)) {
                return continueTo(searchStreet);
            }
            var ids = context.selectedIDs();
            if (mode.id !== 'select' || !ids.length || ids[0] !== springStreetId) {
                // keep Spring Street selected..
                context.enter(modeSelect(context, [springStreetId]));
            }
        });

        context.history().on('change.intro', function() {
            if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
                timeout(function() {
                    continueTo(searchStreet);
                }, 300);  // after any transition (e.g. if user deleted intersection)
            }
        });

        function continueTo(nextStep) {
            context.map().on('move.intro drawn.intro', null);
            context.on('enter.intro', null);
            context.history().on('change.intro', null);
            nextStep();
        }
    }


    function editorStreet() {
        var selector = '.entity-editor-pane button.preset-close svg use';
        var href = d3.select(selector).attr('href') || '#icon-close';

        reveal('.entity-editor-pane',
            t('intro.navigation.editor_street', {
                button: icon(href, 'pre-text'),
                field1: onewayField.label(),
                field2: maxspeedField.label()
            })
        );

        context.on('exit.intro', function() {
            continueTo(play);
        });

        context.history().on('change.intro', function() {
            // update the close icon in the tooltip if the user edits something.
            var selector = '.entity-editor-pane button.preset-close svg use';
            var href = d3.select(selector).attr('href') || '#icon-close';

            reveal('.entity-editor-pane',
                t('intro.navigation.editor_street', {
                    button: icon(href, 'pre-text'),
                    field1: onewayField.label().toLowerCase(),
                    field2: maxspeedField.label().toLowerCase()
                }), { duration: 0 }
            );
        });

        function continueTo(nextStep) {
            context.on('exit.intro', null);
            context.history().on('change.intro', null);
            nextStep();
        }
    }


    function play() {
        dispatch.call('done');
        reveal('#id-container',
            t('intro.navigation.play', { next: t('intro.points.title') }), {
                tooltipBox: '.intro-nav-wrap .chapter-point',
                buttonText: t('intro.ok'),
                buttonCallback: function() { reveal('#id-container'); }
            }
        );
    }


    chapter.enter = function() {
        dragMap();
    };


    chapter.exit = function() {
        timeouts.forEach(window.clearTimeout);
        context.on('enter.intro exit.intro', null);
        context.map().on('move.intro drawn.intro', null);
        context.history().on('change.intro', null);
        d3.select('.inspector-wrap').on('wheel.intro', null);
        d3.select('.search-header input').on('keydown.intro keyup.intro', null);
    };


    chapter.restart = function() {
        chapter.exit();
        chapter.enter();
    };


    return utilRebind(chapter, dispatch, 'on');
}
