/**
 * Initialise model overviews
 * @param {string} repo - Repository to load from, in the format user/repo.
 */
export default function(repo) {
    const LICENSES = {
        'CC BY 4.0':       'https://creativecommons.org/licenses/by/4.0/',
        'CC BY-SA':        'https://creativecommons.org/licenses/by-sa/3.0/',
        'CC BY-SA 3.0':    'https://creativecommons.org/licenses/by-sa/3.0/',
        'CC BY-SA 4.0':    'https://creativecommons.org/licenses/by-sa/4.0/',
        'CC BY-NC':        'https://creativecommons.org/licenses/by-nc/3.0/',
        'CC BY-NC 3.0':    'https://creativecommons.org/licenses/by-nc/3.0/',
        'CC BY-NC 4.0':    'https://creativecommons.org/licenses/by-nc/4.0/',
        'CC-BY-NC-SA 3.0': 'https://creativecommons.org/licenses/by-nc-sa/3.0/',
        'GPL':             'https://www.gnu.org/licenses/gpl.html',
        'LGPL':            'https://www.gnu.org/licenses/lgpl.html',
        'MIT':             'https://opensource.org/licenses/MIT'
    };
    const URL = `https://raw.githubusercontent.com/${repo}/master`;
    const models = [...document.querySelectorAll('[data-vue]')]
        .map(el => el.getAttribute('data-vue'));

    document.addEventListener('DOMContentLoaded', ev => {
        fetch(`${URL}/compatibility.json`)
            .then(res => res.json())
            .then(json => models.forEach(modelId => new Vue({
                el: `[data-vue="${modelId}"]`,
                data: {
                    repo: `https://github.com/${repo}`,
                    compat: json.spacy,
                    loading: false,
                    error: false,
                    id: modelId,
                    version: 'n/a',
                    notes: null,
                    sizeFull: null,
                    fullName: null,
                    pipeline: null,
                    description: null,
                    license: null,
                    author: null,
                    url: null,
                    vectors: null,
                    sources: null,
                    uas: null,
                    las: null,
                    tags_acc: null,
                    ents_f: null,
                    ents_p: null,
                    ents_r: null,
                    modelLicenses: LICENSES,
                    spacyVersion: Object.keys(json.spacy)[0]
                },
                computed: {
                    compatVersion() {
                        const res = this.compat[this.spacyVersion][this.id];
                        return res ? `${this.id}-${res[0]}` : false;
                    },
                    orderedCompat() {
                        return Object.keys(this.compat)
                            .filter(v => this.$_isStableVersion(v));
                    },
                    hasAccuracy() {
                        return this.uas || this.las || this.tags_acc || this.ents_f || this.ents_p || this.ents_r;
                    },
                    releaseUrl() {
                        const baseUrl = `${this.repo}/releases`;
                        return `${baseUrl}/${this.fullName ? `/tag/${this.fullName}` : ''}`
                    }
                },
                beforeMount() {
                    const version = this.$_getLatestVersion(this.id);
                    if (version) {
                        this.loading = true;
                        fetch(`${URL}/meta/${this.id}-${version}.json`)
                            .then(res => res.json())
                            .then(json => this.$_updateData(json))
                            .catch(err => { this.error = true });
                    }
                },
                updated() {
                    window.dispatchEvent(new Event('resize'));  // scroll position for progress
                },
                methods: {
                    $_updateData(data) {
                        this.fullName = `${data.lang}_${data.name}-${data.version}`;
                        this.version = data.version;
                        this.sizeFull = data.size;
                        this.pipeline = data.pipeline;
                        this.notes = data.notes;
                        this.description = data.description;
                        this.vectors = this.$_formatVectors(data.vectors);
                        this.sources = data.sources;
                        this.author = data.author;
                        this.url = data.url;
                        this.license = data.license;
                        const accuracy = data.accuracy || {};
                        for (let key of Object.keys(accuracy)) {
                            this[key] = accuracy[key].toFixed(2);
                        }
                        this.loading = false;
                    },

                    $_getLatestVersion(modelId) {
                        for (let [version, models] of Object.entries(this.compat)) {
                            if (this.$_isStableVersion(version) && models[modelId]) {
                                return models[modelId][0];
                            }
                        }
                    },

                    $_formatVectors(data) {
                        if (!data) {
                            return 'n/a';
                        }
                        if (Object.values(data).every(n => n == 0)) {
                            return 'context vectors only';
                        }
                        const { keys, vectors, width } = data;
                        const nKeys = this.$_abbrNum(keys);
                        const nVectors = this.$_abbrNum(vectors);
                        return `${nKeys} keys, ${nVectors} unique vectors (${width} dimensions)`;
                    },

                    /**
                     * Hacky check if a version number is stable and not alpha,
                     * dev or a release candidate
                     */
                    $_isStableVersion(v) {
                        return !v.includes('a') && !v.includes('b') && !v.includes('dev') && !v.includes('rc');
                    },

                    /**
                     * Abbreviate a number, e.g. 14249930 --> 14.25m.
                     * @param {number|string} num - The number to convert.
                     * @param {number} fixed - Number of decimals.
                     */
                    $_abbrNum: function(num = 0, fixed = 1) {
                        const suffixes = ['', 'k', 'm', 'b', 't'];
                        if (num === null || num === 0) return 0;
                        const b = num.toPrecision(2).split('e');
                        const k = (b.length === 1) ? 0 : Math.floor(Math.min(b[1].slice(1), 14) / 3);
                        const n = (k < 1) ? num : num / Math.pow(10, k * 3);
                        const c = (k >= 1 && n >= 100 ) ? Math.round(n) : n.toFixed(fixed);
                        return (c < 0 ? c : Math.abs(c)) + suffixes[k];
                    }
                }
            })))
    });
}