// @ts-nocheck
import config from '../config.js';
import { diacritics, commands, mathCommands, ligatures, fieldTypes } from '../input/constants.js';
const unicode = {};
for (const command in commands) {
    unicode[commands[command]] = command;
}
for (const diacritic in diacritics) {
    unicode[diacritics[diacritic]] = diacritic;
}
for (const ligature in ligatures) {
    unicode[ligatures[ligature]] = ligature;
}
const mathUnicode = {};
for (const command in mathCommands) {
    mathUnicode[mathCommands[command]] = command;
}
const UNSAFE_UNICODE = /[^a-zA-Z0-9\s!"#%&'()*+,\-./:;=?@[\]{}\u0300-\u0308\u030a-\u030c\u0332\u0323\u0327\u0328\u0361\u0326]/g;
const DIACRITIC_PATTERN = /.[\u0300-\u0308\u030a-\u030c\u0332\u0323\u0327\u0328\u0361\u0326]+/g;
const LONE_DIACRITIC_PATTERN = /[\u0300-\u0308\u030a-\u030c\u0332\u0323\u0327\u0328\u0361\u0326]/g;
const listDelimiters = {
    separated: ',',
    list: ' and ',
};
const richTextMappings = {
    i: '\\textit{',
    b: '\\textbf{',
    sc: '\\textsc{',
    sup: '\\textsuperscript{',
    sub: '\\textsubscript{',
    'span style="font-variant:small-caps;"': '\\textsc{',
    'span class="nocase"': '{',
};
function escapeCharacter(char) {
    if (char in unicode) {
        return unicode[char] in ligatures ? unicode[char] : `\\${unicode[char]}{}`;
    }
    else if (char in mathUnicode) {
        return `$\\${mathUnicode[char]}$`;
    }
    else {
        return '';
    }
}
function escapeValue(value) {
    if (!config.format.asciiOnly) {
        return value;
    }
    return value
        .normalize('NFKD')
        .replace(UNSAFE_UNICODE, (char) => escapeCharacter(char))
        .replace(DIACRITIC_PATTERN, (match) => Array.from(match).reduce((subject, diacritic) => `{\\${unicode[diacritic]} ${subject}}`))
        .replace(LONE_DIACRITIC_PATTERN, '');
}
function formatRichText(value) {
    const closingTags = [];
    let tokens = value.split(/<(\/?(?:i|b|sc|sup|sub|span)|span .*?)>/g);
    tokens = tokens.map((token, index) => {
        if (index % 2 === 0) {
            return escapeValue(token);
        }
        else if (token in richTextMappings) {
            closingTags.push('/' + token.split(' ')[0]);
            return richTextMappings[token];
        }
        else if (token === closingTags[closingTags.length - 1]) {
            closingTags.pop();
            return '}';
        }
        else {
            return '';
        }
    });
    return tokens.join('');
}
function formatName(name) {
    if (name.family && !name.prefix && !name.given & !name.suffix) {
        return name.family.includes(listDelimiters.list) ? name.family : `{${name.family}}`;
    }
    const parts = [''];
    if (name.prefix && name.family) {
        parts[0] += name.prefix + ' ';
    }
    if (name.family) {
        parts[0] += name.family;
    }
    if (name.suffix) {
        parts.push(name.suffix);
        parts.push(name.given || '');
    }
    else {
        parts.push(name.given);
    }
    return escapeValue(parts.join(', ').trim());
}
function formatTitle(title) {
    return formatRichText(title)
        .split(/(:\s*)/)
        .map((part, i) => (i % 2 ? part : part.replace(/([^\\])\b([a-z]*[A-Z].*?)\b/g, '$1{$2}')))
        .join('');
}
function formatSingleValue(value, valueType) {
    switch (valueType) {
        case 'title':
            return formatTitle(value);
        case 'literal':
            return formatRichText(value.toString());
        case 'name':
            return formatName(value);
        case 'verbatim':
        case 'uri':
            return value.toString();
        default:
            return escapeValue(value.toString());
    }
}
function formatList(values, valueType, listType) {
    const delimiter = listDelimiters[listType];
    return values
        .map((value) => {
        const formatted = formatSingleValue(value, valueType);
        return formatted.includes(delimiter) ? `{${formatted}}` : formatted;
    })
        .join(delimiter);
}
function formatAnnotationValue(values) {
    if (Array.isArray(values)) {
        return values.map((value) => escapeValue(value).replace(/([;,"])/g, '{$1}')).join(', ');
    }
    else {
        return '"' + escapeValue(values).replace(/(["])/g, '{$1}') + '"';
    }
}
export function format(field, value) {
    if (!(field in fieldTypes)) {
        return formatSingleValue(value, 'verbatim');
    }
    const [listType, valueType] = fieldTypes[field];
    if (listType in listDelimiters) {
        return formatList(value, valueType, listType);
    }
    else {
        return formatSingleValue(value, valueType);
    }
}
export function formatAnnotation(value) {
    const annotations = [];
    if (value.field) {
        annotations.push('=' + formatAnnotationValue(value.field));
    }
    if (value.item) {
        for (const [itemCount, itemValue] of Object.entries(value.item)) {
            if (!itemValue) {
                continue;
            }
            const i = parseInt(itemCount) + 1;
            annotations.push(i + '=' + formatAnnotationValue(itemValue));
        }
    }
    if (value.part) {
        for (const [itemCount, itemValue] of Object.entries(value.part)) {
            if (!itemValue) {
                continue;
            }
            const i = parseInt(itemCount) + 1;
            for (const part in itemValue) {
                if (!itemValue[part]) {
                    continue;
                }
                annotations.push(i + ':' + part + '=' + formatAnnotationValue(itemValue[part]));
            }
        }
    }
    return annotations.join('; ');
}
