import kdbxweb from 'kdbxweb';
import { View } from 'framework/views/view';
import { Scrollable } from 'framework/views/scrollable';
import template from 'templates/import-csv.hbs';
import { EntryModel } from 'models/entry-model';
import { escape } from 'util/fn';

class ImportCsvView extends View {
    parent = '.app__body';

    template = template;

    events = {
        'click .back-button': 'returnToApp',
        'click .import-csv__button-cancel': 'returnToApp',
        'click .import-csv__button-run': 'runImport',
        'change .import-csv__field-select': 'changeMapping',
        'change .import-csv__target-select': 'changeGroup'
    };

    knownFields = [
        { field: 'Title', re: /title|\bname|account/i },
        { field: 'UserName', re: /user|login/i },
        { field: 'Password', re: /pass/i },
        { field: 'URL', re: /url|site/i },
        { field: 'Notes', re: /notes|comment|extra/i }
    ];

    fieldMapping = [];
    targetGroup = undefined;

    constructor(model, options) {
        super(model, options);
        this.appModel = options.appModel;
        this.fileName = options.fileName;
        this.guessFieldMapping();
        this.fillGroups();
        this.initScroll();
    }

    render() {
        super.render({
            headers: this.model.headers,
            rows: this.model.rows,
            fieldMapping: this.fieldMapping,
            groups: this.groups
        });
        this.createScroll({
            root: this.$el.find('.import-csv__body')[0],
            scroller: this.$el.find('.import-csv__body > .scroller')[0],
            bar: this.$el.find('.import-csv__body > .scroller__bar-wrapper > .scroller__bar')[0]
        });
        this.pageResized();
        if (!this.scroll._update) {
            this.scroll._update = this.scroll.update;
            this.scroll.update = this.scrollUpdate.bind(this);
        }
    }

    scrollUpdate() {
        this.scroller.css({ width: 'auto', minWidth: 'auto', maxWidth: 'auto' });
        this.scroll._update();
    }

    returnToApp() {
        this.emit('cancel');
    }

    changeMapping(e) {
        const col = +e.target.dataset.col;
        const field = e.target.value;

        const isBuiltIn = this.knownFields.some(f => f.field === field);
        const mapping = field ? (isBuiltIn ? 'builtin' : 'custom') : 'ignore';

        this.fieldMapping[col] = {
            mapping,
            field
        };

        if (field) {
            let ix = 0;
            for (const mapping of this.fieldMapping) {
                if (mapping.field === field && col !== ix) {
                    mapping.type = 'ignore';
                    mapping.field = '';
                    const select = this.el.querySelector(
                        `.import-csv__field-select[data-col="${ix}"]`
                    );
                    select.value = '';
                }
                ix++;
            }
        }
    }

    guessFieldMapping() {
        const usedFields = {};

        for (const fieldName of this.model.headers.map(f => f.trim())) {
            if (!fieldName || /^(group|grouping)$/i.test(fieldName)) {
                this.fieldMapping.push({ type: 'ignore' });
                continue;
            }

            let found = false;
            for (const { field, re } of this.knownFields) {
                if (!usedFields[field] && re.test(fieldName)) {
                    this.fieldMapping.push({ type: 'builtin', field });
                    usedFields[field] = true;
                    found = true;
                    break;
                }
            }

            if (!found) {
                this.fieldMapping.push({ type: 'custom', field: fieldName });
            }
        }
    }

    fillGroups() {
        this.groups = [];
        for (const file of this.appModel.files) {
            file.forEachGroup(group => {
                let title = escape(group.title);
                for (let parent = group; parent.parentGroup; parent = parent.parentGroup) {
                    title = '&nbsp;&nbsp;' + title;
                }
                this.groups.push({ id: group.id, fileId: file.id, title });
            });
        }
    }

    changeGroup(e) {
        const groupId = e.target.value;
        if (!groupId) {
            this.targetGroup = undefined;
            return;
        }
        const fileId = e.target.querySelector(`option[value="${groupId}"]`).dataset.file;
        const file = this.appModel.files.get(fileId);
        this.targetGroup = file.getGroup(groupId);
    }

    runImport() {
        let group = this.targetGroup;
        let file = group ? group.file : undefined;
        if (!group) {
            const fileName = this.fileName.replace(/\.csv$/i, '');
            file = this.appModel.createNewFile(fileName);
            group = file.groups[0];
        }
        for (const row of this.model.rows) {
            const newEntry = EntryModel.newEntry(group, file);
            for (let ix = 0; ix < row.length; ix++) {
                let value = row[ix];
                if (!value) {
                    continue;
                }
                const mapping = this.fieldMapping[ix];
                if (mapping.type === 'ignore' || !mapping.field) {
                    continue;
                }
                if (mapping.field === 'password') {
                    value = kdbxweb.ProtectedValue.fromString(value);
                }
                newEntry.setField(mapping.field, value);
            }
        }
        file.reload();
        this.emit('done');
    }
}

Object.assign(ImportCsvView.prototype, Scrollable);

export { ImportCsvView };
