import * as d3 from 'd3';
import _ from 'lodash';
import { t } from '../util/locale';
// import { d3combobox } from '../lib/d3.combobox.js';
import { osmChangeset } from '../osm';
import { modeSelect } from '../modes';
import { svgIcon } from '../svg';
import { tooltip } from '../util/tooltip';
import { uiChangesetEditor } from './changeset_editor';
import { uiRawTagEditor } from './raw_tag_editor';
import { utilDetect } from '../util/detect';
import {
    utilDisplayName,
    utilDisplayType,
    utilEntityOrMemberSelector,
    utilRebind,
    // utilTriggerEvent
} from '../util';


var changeset;
var readOnlyTags = ['created_by', 'imagery_used', 'host', 'locale'];


export function uiCommit(context) {
    var dispatch = d3.dispatch('cancel', 'save'),
        _selection;

    var changesetEditor = uiChangesetEditor(context)
        .on('change', changeTags);
    var rawTagEditor = uiRawTagEditor(context)
        .on('change', changeTags);


    function commit(selection) {
        _selection = selection;

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

        var changes = context.history().changes(),
            summary = context.history().difference().summary(),
            comment = context.storage('comment') || '',
            commentDate = +context.storage('commentDate') || 0,
            currDate = Date.now(),
            cutoff = 2 * 86400 * 1000;   // 2 days

        // expire the stored comment if it is too old - #3947
        if (commentDate > currDate || currDate - commentDate > cutoff) {
            comment = '';
        }

        var tags;
        if (!changeset) {
            var detected = utilDetect();
            tags = {
                comment: comment,
                created_by: ('iD ' + context.version).substr(0, 255),
                imagery_used: context.history().imageryUsed().join(';').substr(0, 255),
                host: detected.host.substr(0, 255),
                locale: detected.locale.substr(0, 255)
            };

            changeset = new osmChangeset({ tags: tags });
        }

        tags = _.clone(changeset.tags);

        var header = selection.selectAll('.header')
            .data([0]);

        header.enter()
            .append('div')
            .attr('class', 'header fillL')
            .append('h3')
            .text(t('commit.title'));

        var body = selection.selectAll('.body')
            .data([0]);

        body = body.enter()
            .append('div')
            .attr('class', 'body')
            .merge(body);


        // Changeset Section
        var changesetSection = body.selectAll('.changeset-editor')
            .data([0]);

        changesetSection = changesetSection.enter()
            .append('div')
            .attr('class', 'modal-section changeset-editor')
            .merge(changesetSection);

        changesetSection
            .call(changesetEditor
                .changesetID(changeset.id)
                .tags(tags)
            );


        // // Fields
        // var fieldSection = body
        //     .append('div')
        //     .attr('class', 'modal-section form-field commit-form');

        // fieldSection
        //     .append('label')
        //     .attr('class', 'form-label')
        //     .text(t('commit.message_label'));

        // var commentField = fieldSection
        //     .append('textarea')
        //     .attr('class', 'commit-form-comment')
        //     .attr('placeholder', t('commit.description_placeholder'))
        //     .attr('maxlength', 255)
        //     .property('value', comment)
        //     .on('input.save', changeComment(true))
        //     .on('change.save', changeComment())
        //     .on('blur.save', function() {
        //         context.storage('comment', this.value);
        //         context.storage('commentDate', Date.now());
        //     });


        // commentField.node().select();

        // osm.userChangesets(function (err, changesets) {
        //     if (err) return;

        //     var comments = changesets.map(function(changeset) {
        //         return {
        //             title: changeset.tags.comment,
        //             value: changeset.tags.comment
        //         };
        //     });

        //     commentField
        //         .call(d3combobox()
        //             .container(context.container())
        //             .caseSensitive(true)
        //             .data(_.uniqBy(comments, 'title'))
        //         );
        // });

        // var commentWarning = fieldSection.append('div')
        //     .attr('class', 'field-warning comment-warning');

        // var changeSetInfo = fieldSection.append('div')
        //     .attr('class', 'changeset-info');

        // changeSetInfo.append('a')
        //     .attr('target', '_blank')
        //     .attr('tabindex', -1)
        //     .call(svgIcon('#icon-out-link', 'inline'))
        //     .attr('href', t('commit.about_changeset_comments_link'))
        //     .append('span')
        //     .text(t('commit.about_changeset_comments'));


        // Warnings
        var warnings = context.history().validate(changes);
        var warningSection = body.selectAll('div.warning-section')
            .data(warnings.length ? [0] : []);

        warningSection.exit()
            .remove();

        var warningEnter = warningSection.enter()
            .append('div')
            .attr('class', 'modal-section warning-section fillL2');

        warningEnter
            .append('h3')
            .text(t('commit.warnings'));

        warningEnter
            .append('ul')
            .attr('class', 'changeset-list');

        warningSection = warningEnter
            .merge(warningSection);


        var warningItems = warningSection.select('ul').selectAll('li')
            .data(warnings);

        warningItems.exit()
            .remove();

        warningItems = warningItems.enter()
            .append('li')
            .on('mouseover', mouseover)
            .on('mouseout', mouseout)
            .on('click', warningClick)
            .merge(warningItems);

        warningItems
            .call(svgIcon('#icon-alert', 'pre-text'));

        warningItems
            .append('strong')
            .text(function(d) { return d.message; });

        warningItems.filter(function(d) { return d.tooltip; })
            .call(tooltip()
                .title(function(d) { return d.tooltip; })
                .placement('top')
            );


        // Upload Explanation
        var saveSection = body.selectAll('.save-section')
            .data([0]);

        saveSection = saveSection.enter()
            .append('div')
            .attr('class','modal-section save-section fillL cf')
            .merge(saveSection);

        var prose = saveSection.selectAll('.commit-info')
            .data([0]);

        prose = prose.enter()
            .append('p')
            .attr('class', 'commit-info')
            .text(t('commit.upload_explanation'))
            .merge(prose);

        osm.userDetails(function(err, user) {
            if (err) return;

            var userLink = d3.select(document.createElement('div'));

            if (user.image_url) {
                userLink
                    .append('img')
                    .attr('src', user.image_url)
                    .attr('class', 'icon pre-text user-icon');
            }

            userLink
                .append('a')
                .attr('class','user-info')
                .text(user.display_name)
                .attr('href', osm.userURL(user.display_name))
                .attr('tabindex', -1)
                .attr('target', '_blank');

            prose
                .html(t('commit.upload_explanation_with_user', { user: userLink.html() }));
        });


        var requestReview = saveSection.selectAll('.request-review')
            .data([0]);

        requestReview = requestReview.enter()
            .append('p')
            .attr('class', 'request-review')
            .text(t('commit.request_review'))
            .merge(requestReview);

        var requestReviewField = requestReview.selectAll('input')
            .data([0]);

        requestReviewField = requestReviewField.enter()
            .append('input')
            .attr('type', 'checkbox')
            .merge(requestReviewField);

        requestReviewField
            .property('checked', isReviewRequested(changeset.tags))
            .on('change', toggleRequestReview);


        // Buttons
        var buttonSection = saveSection.selectAll('.buttons')
            .data([0]);

        // enter
        var buttonEnter = buttonSection.enter()
            .append('div')
            .attr('class', 'buttons fillL cf');

        buttonEnter
            .append('button')
            .attr('class', 'secondary-action col5 button cancel-button')
            .append('span')
            .attr('class', 'label')
            .text(t('commit.cancel'));

        buttonEnter
            .append('button')
            .attr('class', 'action col5 button save-button')
            .append('span')
            .attr('class', 'label')
            .text(t('commit.save'));

        // update
        buttonSection = buttonSection
            .merge(buttonEnter);

        buttonSection.selectAll('.cancel-button')
            .on('click.cancel', function() {
                dispatch.call('cancel');
            });

        buttonSection.selectAll('.save-button')
            .attr('disabled', function() {
                var n = d3.select('.commit-form textarea').node();
                return (n && n.value.length) ? null : true;
            })
            .on('click.save', function() {
                dispatch.call('save', this, changeset);
            });


        // Raw Tag Editor
        var tagSection = body.selectAll('.tag-section.raw-tag-editor')
            .data([0]);

        tagSection = tagSection.enter()
            .append('div')
            .attr('class', 'modal-section tag-section raw-tag-editor')
            .merge(tagSection);

        var expanded = !tagSection.selectAll('a.hide-toggle.expanded').empty();
        tagSection
            .call(rawTagEditor
                .expanded(expanded)
                .readOnlyTags(readOnlyTags)
                .tags(_.clone(changeset.tags))
            );


// TODO check this below (maybe refactor to own module)...

        // Changes
        var changeSection = body.selectAll('.modal-section.commit-section')
            .data([0]);

        var changeEnter = changeSection.enter()
            .append('div')
            .attr('class', 'commit-section modal-section fillL2');

        changeEnter
            .append('h3')
            .text(t('commit.changes', { count: summary.length }));

        var li = changeEnter
            .append('ul')
            .attr('class', 'changeset-list')
            .selectAll('li')
            .data(summary);

        li = li.enter()
            .append('li')
            .on('mouseover', mouseover)
            .on('mouseout', mouseout)
            .on('click', zoomToEntity)
            .merge(li);

        li.each(function(d) {
            d3.select(this)
                .call(svgIcon('#icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
        });

        li.append('span')
            .attr('class', 'change-type')
            .text(function(d) { return t('commit.' + d.changeType) + ' '; });

        li.append('strong')
            .attr('class', 'entity-type')
            .text(function(d) {
                var matched = context.presets().match(d.entity, d.graph);
                return (matched && matched.name()) || utilDisplayType(d.entity.id);
            });

        li.append('span')
            .attr('class', 'entity-name')
            .text(function(d) {
                var name = utilDisplayName(d.entity) || '',
                    string = '';
                if (name !== '') string += ':';
                return string += ' ' + name;
            });

        li.style('opacity', 0)
            .transition()
            .style('opacity', 1);


        // // Call changeComment() off the bat, in case a changeset
        // // comment is recovered from localStorage
        // utilTriggerEvent(commentField, 'input');


        function mouseover(d) {
            if (d.entity) {
                context.surface().selectAll(
                    utilEntityOrMemberSelector([d.entity.id], context.graph())
                ).classed('hover', true);
            }
        }


        function mouseout() {
            context.surface().selectAll('.hover')
                .classed('hover', false);
        }


        function warningClick(d) {
            if (d.entity) {
                context.map().zoomTo(d.entity);
                context.enter(modeSelect(context, [d.entity.id]));
            }
        }


        function zoomToEntity(change) {
            var entity = change.entity;
            if (change.changeType !== 'deleted' &&
                context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
                context.map().zoomTo(entity);
                context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph()))
                    .classed('hover', true);
            }
        }


        // function checkComment(comment) {
        //     // Save button disabled if there is no comment..
        //     d3.selectAll('.save-section .save-button')
        //         .attr('disabled', (comment.length ? null : true));

        //     // // Warn if comment mentions Google..
        //     // var googleWarning = commentWarning
        //     //    .html('')
        //     //    .selectAll('a')
        //     //    .data(comment.match(/google/i) ? [true] : []);

        //     // googleWarning.exit()
        //     //     .remove();

        //     // googleWarning.enter()
        //     //    .append('a')
        //     //    .attr('target', '_blank')
        //     //    .attr('tabindex', -1)
        //     //    .call(svgIcon('#icon-alert', 'inline'))
        //     //    .attr('href', t('commit.google_warning_link'))
        //     //    .append('span')
        //     //    .text(t('commit.google_warning'));
        // }


        // function changeComment(onInput) {
        //     return function() {
                // var comment = commentField.property('value').trim();
                // if (!onInput) {
                //     commentField.property('value', comment);
                // }

                // checkComment(comment);

                // var changeset = updateChangeset({ comment: comment }, onInput);
                // var expanded = !tagSection.selectAll('a.hide-toggle.expanded').empty();

                // changesetSection
                //     .call(changesetEditor
                //         .changeset(changeset)
                //     );

                // tagSection
                //     .call(rawTagEditor
                //         .expanded(expanded)
                //         .readOnlyTags(readOnlyTags)
                //         .tags(_.clone(changeset.tags))
                //     );
        //     };
        // }


        function toggleRequestReview() {
            var rr = requestReviewField.property('checked');
            updateChangeset({ review_requested: (rr ? 'yes' : undefined) });

            var expanded = !tagSection.selectAll('a.hide-toggle.expanded').empty();

            tagSection
                .call(rawTagEditor
                    .expanded(expanded)
                    .readOnlyTags(readOnlyTags)
                    .tags(_.clone(changeset.tags))
                );
        }

    }

    function changeTags(changed, onInput) {
        // if (changed.hasOwnProperty('comment')) {
        //     if (changed.comment === undefined) {
        //         changed.comment = '';
        //     }
        //     changed.comment = changed.comment.trim();
        //     commentField
        //         .property('value', changed.comment);
        // }
        if (changed.hasOwnProperty('comment')) {
            if (changed.comment === undefined) {
                changed.comment = '';
            }
            // if (!onInput) {
            //     changed.comment = changed.comment.trim();
            // }
            // commentField
            //     .property('value', changed.comment);

        }

        // if (changed.hasOwnProperty('review_requested')) {
            // if (changed.review_requested === undefined) {
                // requestReviewField
                //     .property('checked', false);
            // } else {
                // changed.review_requested = changed.review_requested.trim();
                // requestReviewField
                //     .property('checked', isReviewRequested(changed));
            // }
        // }

        updateChangeset(changed, onInput);

        // if (changed.hasOwnProperty('comment')) {
        //     checkComment(changed.comment);
        // }

        if (_selection) {
            _selection.call(commit);
        }
        // utilTriggerEvent(commentField, 'input');
    }


    function isReviewRequested(tags) {
        var rr = tags.review_requested;
        if (rr === undefined) return false;
        rr = rr.trim().toLowerCase();
        return !(rr === '' || rr === 'no');
    }


    function updateChangeset(changed, onInput) {
        var tags = _.clone(changeset.tags);

        _.forEach(changed, function(v, k) {
            k = k.trim().substr(0, 255);
            if (readOnlyTags.indexOf(k) !== -1) return;

            if (k !== '' && v !== undefined) {
                if (onInput) {
                    tags[k] = v;
                } else {
                    tags[k] = v.trim().substr(0, 255);
                }
            } else {
                delete tags[k];
            }
        });

        if (!_.isEqual(changeset.tags, tags)) {
            changeset = changeset.update({ tags: tags });
        }
    }



    commit.reset = function() {
        changeset = null;
    };


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