"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ibanRegExp = exports.ssinRegExp = exports.nihiiRegExp = void 0;
exports.isValidIBAN = isValidIBAN;
exports.ibanValidate = ibanValidate;
exports.ibanFormat = ibanFormat;
exports.nihiiFormat = nihiiFormat;
exports.nihiiValidate = nihiiValidate;
exports.ssinFormat = ssinFormat;
exports.ssinValidate = ssinValidate;
exports.phoneNumberFormat = phoneNumberFormat;
exports.dateDecode = dateDecode;
exports.timeDecode = timeDecode;
exports.dateEncode = dateEncode;
exports.timeEncode = timeEncode;
exports.unit = unit;
exports.amount = amount;
exports.money = money;
exports.toUrlParams = toUrlParams;
exports.personName = personName;
exports.personNameAbbrev = personNameAbbrev;
exports.toMoment = toMoment;
const libphonenumber_js_1 = require("libphonenumber-js");
const date_fns_1 = require("date-fns");
// TODO: move this to env.js?
const DEFAULT_COUNTRY = 'BE';
exports.nihiiRegExp = new RegExp('^(\\d{1})(\\d{5})(\\d{2})(\\d{3})$');
exports.ssinRegExp = new RegExp('^(\\d{2})(\\d{2})(\\d{2})(\\d{3})(\\d{2})$');
exports.ibanRegExp = new RegExp('^(\\d{4})(\\d{4})(\\d{4})(\\d{4})$');
const patterns = {
    IBAN: (iban) => /^BE\d{14}$/.test(iban) && isValidIBAN(iban),
    IBANBE: (iban) => /^BE\d{14}$/.test(iban) && isValidIBAN(iban),
};
//http://ht5ifv.serprest.pt/extensions/tools/IBAN/
function isValidIBAN(iban) {
    //This function check if the checksum if correct
    iban = iban.replace(/^(.{4})(.*)$/, '$2$1'); //Move the first 4 chars from left to the right
    const fun = (e) => (e.charCodeAt(0) - 'A'.charCodeAt(0) + 10).toString();
    iban = iban.replace(/[A-Z]/g, fun); //Convert A-Z to 10-25
    let $sum = 0;
    let $ei = 1; //First exponent
    for (let $i = iban.length - 1; $i >= 0; $i--) {
        $sum += $ei * parseInt(iban.charAt($i), 10); //multiply the digit by it's exponent
        $ei = ($ei * 10) % 97; //compute next base 10 exponent  in modulus 97
    }
    return $sum % 97 === 1;
}
function ibanValidate(iban) {
    if (iban.startsWith('BE')) {
        return patterns.IBANBE(iban);
    }
    else {
        return patterns.IBAN(iban);
    }
}
function ibanFormat(iban) {
    return iban.replace(exports.ibanRegExp, '$1 $2 $3 $4');
}
function nihiiFormat(nihii) {
    return nihii.replace(exports.nihiiRegExp, '$1 $2 $3 $4');
}
function nihiiValidate(nihii) {
    return !!nihii.match(exports.nihiiRegExp);
}
function ssinFormat(ssin) {
    return ssin.replace(exports.ssinRegExp, '$1 $2 $3 $4 $5');
}
function ssinValidate(ssin) {
    return !!ssin.match(exports.ssinRegExp);
}
/* Alternate lib free version
export function phoneNumberValidate(phoneNumber: string): boolean {
  return (
    !!phoneNumber.match(/(?:\+|00)([1-9][0-9]{1-2})([- /.]*([0-9]+))+/) ||
    !!phoneNumber.match(/(0[1-9][0-9]*)([- /.]*([0-9]+))+/)
  )
}

export function phoneNumberFormat(phoneNumber: string): string {
  let match = phoneNumber.match(/(?:\+|00)([1-9][0-9]{1-2})([- /.]*([0-9]+))+/)
  if (match) {
    return `+${match[1]} ${match[2].replace(/[- /.]/g, " ")}`.replace(/  /g, " ")
  }
  match = phoneNumber.match(/0([1-9][0-9]*)([- /.]*([0-9]+))+/)
  if (match) {
    return `+32 ${match[1]} ${match[2].replace(/[- /.]/g, " ")}`.replace(/  /g, " ")
  }
  return phoneNumber
}
*/
function phoneNumberFormat(phoneNumber) {
    const parsedPhoneNumber = (0, libphonenumber_js_1.parseNumber)(phoneNumber, DEFAULT_COUNTRY);
    if (Object.keys(parsedPhoneNumber).length === 0) {
        // The number is not valid, so we leave the input string as-is.
        return phoneNumber;
    }
    return (0, libphonenumber_js_1.formatNumber)(parsedPhoneNumber, 'INTERNATIONAL');
}
/**
 * Converts a backend date number (e.g., patient birth date) into a Date object.
 * @param dateNumber a YYYYMMDD date number from the backend
 * @return a Date object
 * @throws Error if it is impossible to create a date from the number, other if dateNumber is negative.
 * @see #dateEncode
 * @see #timeDecode
 */
function dateDecode(dateNumber) {
    if (!dateNumber) {
        return undefined;
    }
    if (dateNumber < 0) {
        throw new Error("We don't decode negative dates. Please make sure you have valid data.");
    }
    const dateNumberStr = dateNumber.toString().padStart(8, '19700101');
    if (dateNumberStr.length > 8) {
        if (dateNumberStr.endsWith('000000')) {
            return dateNumber ? (0, date_fns_1.parse)(dateNumberStr.slice(0, 8), 'yyyyMMdd', new Date()) : undefined;
        }
        throw Error("Decoded date is over year 9999. We can't format it properly.");
    }
    return dateNumber ? (0, date_fns_1.parse)(dateNumberStr, 'yyyyMMdd', new Date()) : undefined;
}
/**
 * Converts a backend time number (e.g., health element openingDate) into a Date object.
 * @param timeNumber a YYYYMMDD date number from the backend
 * @return a Date object
 * @see #timeEncode
 * @see #dateDecode
 */
function timeDecode(timeNumber) {
    return timeNumber ? (0, date_fns_1.parse)(timeNumber.toString(), 'yyyyMMddHHmmss', new Date()) : undefined;
}
/**
 * Encodes a Date object into a backend date number (e.g., patient birth date).
 * @param date a Date object
 * @return a YYYYMMDD date number for the backend
 * @see #dateDecode
 * @see #timeEncode
 */
function dateEncode(date) {
    const dateStr = (0, date_fns_1.format)(date, 'yyyyMMdd').padStart(8, '19700101');
    // date is null if the field is not set
    return date ? Number(dateStr) : undefined;
}
/**
 * Encodes a Date object into a backend time number (e.g., health element openingDate).
 * @param date a Date object
 * @return a YYYYMMDDHHmmss date number for the backend
 * @see #timeDecode
 * @see #dateEncode
 */
function timeEncode(date) {
    return date ? Number((0, date_fns_1.format)(date, 'yyyyMMddHHmmss')) : undefined;
}
/**
 * Formats a value and a physical unit into text.
 * @param value the numerical or string value to encode
 * @param unit the unit represented as a string (an empty string is also supported)
 */
function unit(value, unit) {
    unit = unit || '';
    let separator;
    if (!unit || unit.startsWith('°')) {
        separator = '';
    }
    else {
        // including '%'
        separator = '\xa0';
    }
    return value + separator + unit;
}
/**
 * 0.1 + 0.2 = 0.30000000000000004. Use this function to be better at maths.
 * @param a number
 * @return the rounded number, two after the comma
 */
function amount(value) {
    return Number((value || 0).toFixed(2));
}
/**
 * A simple formatter to keep the logic across the app.
 * Input: 2.1 ; Output: 2.10€
 */
function money(value) {
    return [(value || 0).toFixed(2), '€'].join('');
}
/**
 * Transform a dictionary to a url params.
 * From { key1: value1, key2: value2, ... } returns key1=value1&key2=value2&...=...
 */
function toUrlParams(params) {
    return Object.entries(params)
        .map(([key, value]) => (value ? key + '=' + value : undefined))
        .filter(Boolean)
        .join('&');
}
function personName(person) {
    return `${person.firstName || ''} ${person.lastName || ''}`.trim();
}
function personNameAbbrev(person) {
    const firstName = person.firstName ? person.firstName[0] + '.' : undefined;
    return personName(Object.assign(Object.assign({}, person), { firstName }));
}
function toMoment(epochOrLongCalendar) {
    if (!epochOrLongCalendar && epochOrLongCalendar !== 0) {
        return null;
    }
    const parsed = (epochOrLongCalendar >= 18000101 && epochOrLongCalendar < 25400000) ?
        (0, date_fns_1.parse)('' + epochOrLongCalendar, 'yyyyMMdd', new Date()) :
        (epochOrLongCalendar >= 18000101000000) ?
            (0, date_fns_1.parse)('' + epochOrLongCalendar, 'yyyyMMddHHmmss', new Date()) :
            new Date(epochOrLongCalendar);
    return {
        format: (format) => {
            return (0, date_fns_1.format)(parsed, format);
        }
    };
}
//# sourceMappingURL=formatting-util.js.map