import { select as d3_select } from 'd3-selection';
import { t } from '../core/localizer';

import { modeBrowse } from './browse';
import { services } from '../services';
import { uiConflicts } from '../ui/conflicts';
import { uiConfirm } from '../ui/confirm';
import { uiCommit } from '../ui/commit';
import { uiSuccess } from '../ui/success';
import { utilKeybinding } from '../util';


export function modeSave(context) {
    var mode = { id: 'save' };
    var keybinding = utilKeybinding('modeSave');

    var commit = uiCommit(context)
        .on('cancel', cancel);
    var _conflictsUi; // uiConflicts

    var _location;
    var _success;

    var uploader = context.uploader()
        .on('saveStarted.modeSave', function() {
            keybindingOff();
        })
        // fire off some async work that we want to be ready later
        .on('willAttemptUpload.modeSave', prepareForSuccess)
        .on('progressChanged.modeSave', showProgress)
        .on('resultNoChanges.modeSave', function() {
            cancel();
        })
        .on('resultErrors.modeSave', showErrors)
        .on('resultConflicts.modeSave', showConflicts)
        .on('resultSuccess.modeSave', showSuccess);


    function cancel() {
        context.enter(modeBrowse(context));
    }


    function showProgress(num, total) {
        var modal = context.container().select('.loading-modal .modal-section');
        var progress = modal.selectAll('.progress')
            .data([0]);

        // enter/update
        progress.enter()
            .append('div')
            .attr('class', 'progress')
            .merge(progress)
            .text(t('save.conflict_progress', { num: num, total: total }));
    }


    function showConflicts(changeset, conflicts, origChanges) {

        var selection = context.container()
            .select('.sidebar')
            .append('div')
            .attr('class','sidebar-component');

        context.container().selectAll('.main-content')
            .classed('active', true)
            .classed('inactive', false);

        _conflictsUi = uiConflicts(context)
            .conflictList(conflicts)
            .origChanges(origChanges)
            .on('cancel', function() {
                context.container().selectAll('.main-content')
                    .classed('active', false)
                    .classed('inactive', true);
                selection.remove();
                keybindingOn();

                uploader.cancelConflictResolution();
            })
            .on('save', function() {
                context.container().selectAll('.main-content')
                    .classed('active', false)
                    .classed('inactive', true);
                selection.remove();

                uploader.processResolvedConflicts(changeset);
            });

        selection.call(_conflictsUi);
    }


    function showErrors(errors) {
        keybindingOn();

        var selection = uiConfirm(context.container());
        selection
            .select('.modal-section.header')
            .append('h3')
            .text(t('save.error'));

        addErrors(selection, errors);
        selection.okButton();
    }


    function addErrors(selection, data) {
        var message = selection
            .select('.modal-section.message-text');

        var items = message
            .selectAll('.error-container')
            .data(data);

        var enter = items.enter()
            .append('div')
            .attr('class', 'error-container');

        enter
            .append('a')
            .attr('class', 'error-description')
            .attr('href', '#')
            .classed('hide-toggle', true)
            .text(function(d) { return d.msg || t('save.unknown_error_details'); })
            .on('click', function(d3_event) {
                d3_event.preventDefault();

                var error = d3_select(this);
                var detail = d3_select(this.nextElementSibling);
                var exp = error.classed('expanded');

                detail.style('display', exp ? 'none' : 'block');
                error.classed('expanded', !exp);
            });

        var details = enter
            .append('div')
            .attr('class', 'error-detail-container')
            .style('display', 'none');

        details
            .append('ul')
            .attr('class', 'error-detail-list')
            .selectAll('li')
            .data(function(d) { return d.details || []; })
            .enter()
            .append('li')
            .attr('class', 'error-detail-item')
            .text(function(d) { return d; });

        items.exit()
            .remove();
    }


    function showSuccess(changeset) {
        commit.reset();

        var ui = _success
            .changeset(changeset)
            .location(_location)
            .on('cancel', function() { context.ui().sidebar.hide(); });

        context.enter(modeBrowse(context).sidebar(ui));
    }


    function keybindingOn() {
        d3_select(document)
            .call(keybinding.on('⎋', cancel, true));
    }


    function keybindingOff() {
        d3_select(document)
            .call(keybinding.unbind);
    }


    // Reverse geocode current map location so we can display a message on
    // the success screen like "Thank you for editing around place, region."
    function prepareForSuccess() {
        _success = uiSuccess(context);
        _location = null;
        if (!services.geocoder) return;

        services.geocoder.reverse(context.map().center(), function(err, result) {
            if (err || !result || !result.address) return;

            var addr = result.address;
            var place = (addr && (addr.town || addr.city || addr.county)) || '';
            var region = (addr && (addr.state || addr.country)) || '';
            var separator = (place && region) ? t('success.thank_you_where.separator') : '';

            _location = t('success.thank_you_where.format',
                { place: place, separator: separator, region: region }
            );
        });
    }


    mode.selectedIDs = function() {
        return _conflictsUi ? _conflictsUi.shownEntityIds() : [];
    };


    mode.enter = function() {
        // Show sidebar
        context.ui().sidebar.expand();

        function done() {
            context.ui().sidebar.show(commit);
        }

        keybindingOn();

        context.container().selectAll('.main-content')
            .classed('active', false)
            .classed('inactive', true);

        var osm = context.connection();
        if (!osm) {
            cancel();
            return;
        }

        if (osm.authenticated()) {
            done();
        } else {
            osm.authenticate(function(err) {
                if (err) {
                    cancel();
                } else {
                    done();
                }
            });
        }
    };


    mode.exit = function() {

        keybindingOff();

        context.container().selectAll('.main-content')
            .classed('active', true)
            .classed('inactive', false);

        context.ui().sidebar.hide();
    };

    return mode;
}
