// import { Csv2md } from 'csv2md'
import { parse } from 'csv-parse/browser/esm/sync';
import typeOf from 'type-detect';
import escapeSqlString from 'sql-escape-string';
import { unflattenObject, flattenObjectSafe, } from '../../../../code/tool/shared/object';
import _ from 'lodash';
import sortKeys from 'json-keys-sort';
// let csv2md = new Csv2md({
//   pretty: true,
// })
// export async function convertCSVToMarkdownTable(text: string) {
//   let markdown = await csv2md.convert(text)
//   return markdown
// }
export async function convertCSVToJSON(text, { trim = true, columns = true, bom = true, objname, group_columns_by_name, skip_empty_lines, record_delimiter, nested_delimiter = '.', }) {
    const records = parse(text, {
        trim,
        columns,
        bom,
        objname,
        group_columns_by_name,
        skip_empty_lines,
        record_delimiter,
    }).map((record) => unflattenObject(record, nested_delimiter));
    return records;
}
export function convertJsonToSql(records) {
    const table = convertJsonToTable(records);
    return convertTableToPostgresqlOrMySql('table', table);
}
export function convertTableToPostgresqlOrMySql(name, table) {
    const text = [];
    text.push(`CREATE TABLE \`${name}\` (`);
    for (const name in table.columns) {
        const column = table.columns[name];
        if (column.type === 'json') {
            text.push(`  \`${name}\` JSON,`);
        }
        else if (column.type === 'boolean') {
            text.push(`  \`${name}\` BOOLEAN,`);
        }
        else if (column.type === 'string') {
            text.push(`  \`${name}\` VARCHAR(${column.size}),`);
        }
        else if (column.type === 'integer' ||
            column.type === 'natural_number') {
            if (column.min != null && column.max != null) {
                if (column.min >= -32768 && column.max <= 32767) {
                    text.push(`  \`${name}\` SMALLINT,`);
                }
                else if (column.min >= -2147483648 &&
                    column.max <= 2147483647) {
                    text.push(`  \`${name}\` INTEGER,`);
                }
                else if (BigInt(column.min) >= -9223372036854775808n &&
                    BigInt(column.max) <= 9223372036854775807n) {
                    text.push(`  \`${name}\` BIGINT,`);
                }
            }
        }
        else if (column.type === 'float') {
            if (column.precision != null) {
                if (column.precision <= 6) {
                    text.push(`  \`${name}\` REAL,`);
                }
                else if (column.precision <= 15) {
                    text.push(`  \`${name}\` DOUBLE PRECISION,`);
                }
                else {
                    text.push(`  \`${name}\` DECIMAL,`);
                }
            }
        }
    }
    text.push(`);`);
    text.push(``);
    text.push(`INSERT INTO \`${name}\` VALUES`);
    table.rows.forEach(row => {
        const line = [];
        for (let i = 0; i < row.length; i++) {
            const val = row[i];
            const column = table.columnByIndex[i];
            if (column.type === 'string') {
                line.push(escapeSqlString(val ? val : ''));
            }
            else if (column.type === 'json') {
                line.push(escapeSqlString(JSON.stringify(val)));
            }
            else {
                line.push(val);
            }
        }
        text.push(`(${line.join(', ')})`);
    });
    return text.join('\n');
}
// https://www.npmjs.com/package/sqlstring
export function convertJsonToTable(records) {
    const table = {
        columnIndex: 0,
        columns: {},
        columnByIndex: {},
        rows: [],
    };
    records.forEach(record => {
        const flattened = sortKeys.sort(flattenObjectSafe(record));
        const row = [];
        table.rows.push(row);
        for (const name in flattened) {
            if (!table.columns[name]) {
                table.columnByIndex[table.columnIndex] = table.columns[name] = {
                    types: {},
                    index: table.columnIndex,
                };
                table.columnIndex++;
            }
            let column = table.columns[name];
            let value = flattened[name];
            let type = typeOf(value);
            if (type === 'number') {
                column.min = Math.min(column.min || 0, value);
                column.max = Math.max(column.max || 0, value);
                if (_.isInteger(value)) {
                    if (value >= 0) {
                        type = 'uint';
                    }
                    else {
                        type = 'int';
                    }
                }
                else {
                    type = 'float';
                    column.precision = Math.max(String(value).split('.').pop()?.length ?? 1, column.precision ?? 1);
                }
            }
            else if (type === 'Array') {
                type = 'json';
            }
            else if (type === 'boolean') {
                type = 'boolean';
            }
            else if (type === 'string') {
                column.size = Math.max(column.size || 4, value.length);
            }
            else {
                throw new Error(`${type} not handled yet.`);
            }
            column.types[type] = true;
            row[column.index] = value;
        }
    });
    const newTable = {
        columns: {},
        columnByIndex: {},
        rows: table.rows,
    };
    for (const name in table.columns) {
        const column = table.columns[name];
        delete table.columns[name];
        if (column.types.json) {
            newTable.columnByIndex[column.index] = newTable.columns[name] = {
                type: 'json',
            };
        }
        else if (column.types.string) {
            newTable.columnByIndex[column.index] = newTable.columns[name] = {
                type: 'string',
                size: roundNearestMultiple(column.size ?? 8, 8),
            };
        }
        else if (column.types.float) {
            newTable.columnByIndex[column.index] = newTable.columns[name] = {
                type: 'float',
                precision: column.precision,
            };
        }
        else if (column.types.int) {
            newTable.columnByIndex[column.index] = newTable.columns[name] = {
                type: 'integer',
                min: column.min,
                max: column.max,
            };
        }
        else if (column.types.uint) {
            newTable.columnByIndex[column.index] = newTable.columns[name] = {
                type: 'natural_number',
                min: column.min,
                max: column.max,
            };
        }
        else if (column.types.boolean) {
            newTable.columnByIndex[column.index] = newTable.columns[name] = {
                type: 'boolean',
            };
        }
    }
    return newTable;
}
export function roundNearestMultiple(x, n) {
    return Math.ceil(x / n) * n;
}
//# sourceMappingURL=shared.js.map