// @ts-nocheck
import { util } from '../../core/index.js';
import config from '../config.js';
const stopWords = new Set(['the', 'a', 'an']);
const unsafeChars = /(?:<\/?.*?>|[\u0020-\u002F\u003A-\u0040\u005B-\u005E\u0060\u007B-\u007F])+/g;
const unicode = /[^\u0020-\u007F]+/g;
function isLabelSafe(text) {
    return !config.format.checkLabel || !text.match(unsafeChars);
}
function formatLabelFromId(id) {
    if (id === null) {
        return 'null';
    }
    else if (id === undefined) {
        return 'undefined';
    }
    else if (config.format.checkLabel) {
        return id.toString().replace(unsafeChars, '');
    }
    else {
        return id.toString();
    }
}
function firstWord(text) {
    if (!text) {
        return '';
    }
    else {
        return text
            .normalize('NFKD')
            .replace(unicode, '')
            .split(unsafeChars)
            .find((word) => word.length && !stopWords.has(word.toLowerCase()));
    }
}
const name = new util.Translator([
    {
        source: 'given',
        target: 'given',
    },
    {
        source: 'family',
        target: 'family',
    },
    {
        source: 'suffix',
        target: 'suffix',
    },
    {
        source: 'prefix',
        target: 'non-dropping-particle',
    },
    {
        source: 'family',
        target: 'literal',
        when: {
            source: false,
            target: {
                family: false,
                given: false,
            },
        },
    },
]);
const months = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'];
export const TYPE = 'BibTeX type';
export const LABEL = 'BibTeX label';
export const MONTHS = {
    jan: 1,
    feb: 2,
    mar: 3,
    apr: 4,
    may: 5,
    jun: 6,
    jul: 7,
    aug: 8,
    sep: 9,
    oct: 10,
    nov: 11,
    dec: 12,
    january: 1,
    february: 2,
    march: 3,
    april: 4,
    may: 5,
    june: 6,
    july: 7,
    august: 8,
    september: 9,
    october: 10,
    november: 11,
    december: 12,
};
export const TYPE_KEYS = {
    bathesis: "Bachelor's thesis",
    mathesis: "Master's thesis",
    phdthesis: 'PhD thesis',
    candthesis: 'Candidate thesis',
    techreport: 'technical report',
    resreport: 'research report',
    software: 'computer software',
    datacd: 'data cd',
    audiocd: 'audio cd',
    patent: 'patent',
    patentde: 'German patent',
    patenteu: 'European patent',
    patentfr: 'French patent',
    patentuk: 'British patent',
    patentus: 'U.S. patent',
    patreq: 'patent request',
    patreqde: 'German patent request',
    patreqeu: 'European patent request',
    patreqfr: 'French patent request',
    patrequk: 'British patent request',
    patrequs: 'U.S. patent request',
};
export const STANDARD_NUMBERS_PATTERN = /(^(?:ISAN )?(?:[0-9a-f]{4}-){4}[0-9a-z](?:-(?:[0-9a-f]{4}-){2}[0-9a-z])?$)|(^(?:979-?0-?|M-?)(?:\d{9}|(?=[\d-]{11}$)\d+-\d+-\d)$)|(^ISRN .{1,36}$)|(^(?:ISWC )?T-?\d{9}-?\d$)/i;
export function parseDate(date) {
    const parts = date
        .split('T')[0]
        .replace(/[?~%]$/, '')
        .split('-');
    const year = +parts[0].replace(/^Y(?=-?\d{4}\d+)/, '').replace(/X/g, '0');
    const month = +parts[1];
    const day = +parts[2];
    if (!month || month > 20) {
        return [year];
    }
    else if (!day) {
        return [year, month];
    }
    else {
        return [year, month, day];
    }
}
export function parseMonth(value) {
    if (value == null) {
        return [];
    }
    if (+value) {
        return [parseInt(value, 10)];
    }
    value = value.trim().toLowerCase();
    if (value in MONTHS) {
        return [MONTHS[value]];
    }
    const parts = value.split(/\s+/);
    let month;
    let day;
    if (parts[0] in MONTHS) {
        month = MONTHS[parts[0]];
        day = parseInt(parts[1]);
    }
    else if (parts[1] in MONTHS) {
        month = MONTHS[parts[1]];
        day = parseInt(parts[0]);
    }
    return day ? [month, day] : month ? [month] : [];
}
export function formatLabel(author, issued, suffix, title) {
    let label = '';
    if (author && author[0]) {
        label += firstWord(author[0].family || author[0].literal);
    }
    if (issued && issued['date-parts'] && issued['date-parts'][0]) {
        label += issued['date-parts'][0][0];
    }
    if (suffix) {
        label += suffix;
    }
    else if (title) {
        label += firstWord(title);
    }
    return label;
}
export const Converters = {
    PICK: {
        toTarget(...args) {
            return args.find(Boolean);
        },
        toSource(value) {
            return [value];
        },
    },
    DATE: {
        toTarget(date) {
            const parts = date
                .split('/')
                .map((part) => (part && part !== '..' ? parseDate(part) : undefined));
            return isNaN(parts[0][0])
                ? {
                    literal: date,
                }
                : {
                    'date-parts': parts,
                };
        },
        toSource(date) {
            if ('date-parts' in date) {
                return date['date-parts']
                    .map((datePart) => datePart.map((datePart) => datePart.toString().padStart(2, '0')).join('-'))
                    .join('/');
            }
        },
    },
    YEAR_MONTH: {
        toTarget(year, month, day) {
            if (isNaN(+year)) {
                return {
                    literal: year,
                };
            }
            else if (!isNaN(+day) && !isNaN(+month)) {
                return {
                    'date-parts': [[+year, +month, +day]],
                };
            }
            else {
                return {
                    'date-parts': [[+year, ...parseMonth(month)]],
                };
            }
        },
        toSource(date) {
            if ('date-parts' in date) {
                const [year, month, day] = date['date-parts'][0];
                return [year.toString(), month ? (day ? `${months[month - 1]} ${day}` : month) : undefined];
            }
            else {
                return [];
            }
        },
    },
    EPRINT: {
        toTarget(id, type) {
            if (type === 'pubmed') {
                return id;
            }
        },
        toSource(id) {
            return [id, 'pubmed'];
        },
    },
    EVENT_TITLE: {
        toTarget(title, addon) {
            if (addon) {
                title += ' (' + addon + ')';
            }
            return title;
        },
        toSource(title) {
            return title.match(/^(.+)(?: \((.+)\))?$/).slice(1, 3);
        },
    },
    HOW_PUBLISHED: {
        toTarget(howPublished) {
            if (howPublished.startsWith('http')) {
                return howPublished;
            }
        },
    },
    KEYWORDS: {
        toTarget(list) {
            return list.join(',');
        },
        toSource(list) {
            return list.split(',');
        },
    },
    LABEL: {
        toTarget(label) {
            return [label, label];
        },
        toSource(id, label, author, issued, suffix, title) {
            if (label && isLabelSafe(label)) {
                return label;
            }
            else if (config.format.useIdAsLabel) {
                return formatLabelFromId(id);
            }
            else {
                return formatLabel(author, issued, suffix, title) || formatLabelFromId(id);
            }
        },
    },
    NAMES: {
        toTarget(list) {
            return list.map(name.convertToTarget);
        },
        toSource(list) {
            return list.map(name.convertToSource);
        },
    },
    NAMES_ORCID: {
        toTarget(list, orcid) {
            return list.map((inputName, i) => {
                var _orcid$item;
                const outputName = name.convertToTarget(inputName);
                if (typeof (orcid === null ||
                    orcid === void 0 ||
                    (_orcid$item = orcid.item) === null ||
                    _orcid$item === void 0
                    ? void 0
                    : _orcid$item[i]) === 'string') {
                    outputName._orcid = orcid.item[i];
                }
                return outputName;
            });
        },
        toSource(list) {
            const names = [];
            const orcid = [];
            for (let i = 0; i < list.length; i++) {
                names.push(name.convertToSource(list[i]));
                if (list[i]._orcid) {
                    orcid[i] = list[i]._orcid;
                }
            }
            return [
                names,
                orcid.length
                    ? {
                        item: orcid,
                    }
                    : undefined,
            ];
        },
    },
    PAGES: {
        toTarget(pages) {
            return pages.replace(/[–—]/, '-');
        },
        toSource(pages) {
            return pages.replace('-', '--');
        },
    },
    STANDARD_NUMBERS: {
        toTarget(...args) {
            return args.find(Boolean);
        },
        toSource(number) {
            const match = number.toString().match(STANDARD_NUMBERS_PATTERN);
            return match ? match.slice(1, 5) : [];
        },
    },
    STATUS: {
        toSource(state) {
            if (/^(inpreparation|submitted|forthcoming|inpress|prepublished)$/i.test(state)) {
                return state;
            }
        },
    },
    TITLE: {
        toTarget(title, subtitle, addon) {
            if (subtitle) {
                title += ': ' + subtitle;
            }
            return title;
        },
        toSource(title) {
            return [title];
        },
    },
};
