const PHONE_GUESS_MAX_ROWS_PROBED = 200;
const PHONE_GUESS_MINIMUM_HIT_THRESHOLD = 0.5;

const phoneRegexp = /^(\+4|)?(07[0-8]{1}[0-9]{1}|02[0-9]{2}|03[0-9]{2}){1}?(\s|\.|\-)?([0-9]{3}(\s|\.|\-|)){2}$/igm;

function guessPhoneColumns(sheet, validColumns) {

    var rowCount = sheet.data.length;

    if (rowCount == 0) {
        return [];
    }

    // try to guess which columns represent phone numbers based on up to PHONE_GUESS_MAX_ROWS_PROBED rows picked at random

    var rowsToProbe = [];

    var rowIndexStack = [];

    for (var i = 0; i < rowCount; i++) {
        rowIndexStack.push(i);
    }

    if (rowCount <= PHONE_GUESS_MAX_ROWS_PROBED) {
        rowsToProbe = rowIndexStack;
    } else {
        for (var i = 0; i < PHONE_GUESS_MAX_ROWS_PROBED; i++) {
            var row = Math.floor(Math.random() * rowIndexStack.length);
            rowsToProbe.push(row);
            rowIndexStack.splice(row, 1); // remove one from the candidate pool
        }
    }

    var columnMatchStats = validColumns.map(c => {
        return {index: c.value, phoneHitCount: 0};
    });

    rowsToProbe.forEach(rowIndex => {
        var rowData = sheet.data[rowIndex];
        validColumns.forEach((c, i) => {
            var columnValue = rowData[c.value];
            if (columnValue != null) {
                if (phoneRegexp.test(columnValue)) {
                    columnMatchStats[i].phoneHitCount++;
                }
                phoneRegexp.lastIndex = 0; // https://dev.to/newyorkanthonyng/use-stateful-javascript-regular-expressions-4k25
            }
        });
    });

    return columnMatchStats
        .filter(pair => pair.phoneHitCount / rowsToProbe.length >= PHONE_GUESS_MINIMUM_HIT_THRESHOLD)
        .map(pair => pair.index);

}

function getCandidatePhoneNumbers(row, phoneColumns) {

    var phoneSet = new Set();

    phoneColumns.forEach(c => {
        var columnText = row[c];
        if (columnText != null) {
            for (var match of columnText.matchAll(phoneRegexp)) {
                phoneSet.add(match[0]);
            }
        }
    });

    return Array.from(phoneSet);

}

// return number in E164 format
function prepareNumber(number) {
    if (number == null) {
        return null;
    }
    var parsed = libphonenumber.parsePhoneNumberFromString(number, "RO");
    if (parsed == null || Object.keys(parsed).length === 0) {
        return null;
    } else {
        return {
            e164: parsed.number,
            destinationType: parsed.country !== "RO" ? "international" : parsed.number.startsWith("+407") ? "nationalMobile" : "nationalLandline",
            isValid: parsed.isValid()
        }
    }
}

function applyTemplate(templateText, columnNameMap, row) {
    return templateText == null ? "" : templateText.replaceAll(/\${[^}]+}/ig, match => {
        var replacementIndex = columnNameMap.get(match.toLowerCase());
        if (replacementIndex != null) {
            return "" + row.data[replacementIndex];
        } else {
            return match;
        }
    });
}

function delay(fn, t) {
    var timeout = null;

    return function() {
        if (timeout != null) {
            clearTimeout(timeout);
        }
        var args = arguments;
        var that = this;
        timeout = setTimeout(function() {
            fn.apply(that, args);
        }, t)
    };
}