import crypto from 'crypto';
import { databaseTypes, fieldTypes } from '../../../jdl/jhipster/index.mjs';
import { hibernateSnakeCase } from './string.mjs';
import { databaseData } from '../../spring-data-relational/support/index.mjs';
const dbTypes = fieldTypes;
const { STRING: TYPE_STRING, LONG: TYPE_LONG, UUID: TYPE_UUID } = dbTypes.CommonDBTypes;
const { MONGODB, NEO4J, COUCHBASE, CASSANDRA, SQL } = databaseTypes;
const databaseTypeDataFallback = {
    name: 'Unknown',
    defaultPrimaryKeyType: TYPE_LONG,
};
export const databaseTypeData = {
    [CASSANDRA]: {
        name: 'Cassandra',
        defaultPrimaryKeyType: TYPE_UUID,
    },
    [COUCHBASE]: {
        name: 'Couchbase',
        defaultPrimaryKeyType: TYPE_STRING,
    },
    [MONGODB]: {
        name: 'MongoDB',
        defaultPrimaryKeyType: TYPE_STRING,
    },
    [NEO4J]: {
        name: 'Neo4j',
        defaultPrimaryKeyType: TYPE_STRING,
    },
    [SQL]: {
        name: 'SQL',
        defaultPrimaryKeyType: TYPE_LONG,
    },
};
export const getDatabaseTypeData = (databaseType) => {
    return databaseTypeData[databaseType] ?? databaseTypeDataFallback;
};
export const R2DBC_DB_OPTIONS = [
    {
        value: databaseTypes.POSTGRESQL,
        name: 'PostgreSQL',
    },
    {
        value: databaseTypes.MYSQL,
        name: 'MySQL',
    },
    {
        value: databaseTypes.MARIADB,
        name: 'MariaDB',
    },
    {
        value: databaseTypes.MSSQL,
        name: 'Microsoft SQL Server',
    },
];
export const SQL_DB_OPTIONS = [
    {
        value: databaseTypes.POSTGRESQL,
        name: 'PostgreSQL',
    },
    {
        value: databaseTypes.MYSQL,
        name: 'MySQL',
    },
    {
        value: databaseTypes.MARIADB,
        name: 'MariaDB',
    },
    {
        value: databaseTypes.ORACLE,
        name: 'Oracle',
    },
    {
        value: databaseTypes.MSSQL,
        name: 'Microsoft SQL Server',
    },
];
export function getDBTypeFromDBValue(db) {
    if (SQL_DB_OPTIONS.map(db => db.value).includes(db)) {
        return SQL;
    }
    return db;
}
export function calculateDbNameWithLimit(tableOrEntityName, columnOrRelationshipName, limit, { noSnakeCase = false, prefix = '', separator = '__' } = {}) {
    const halfLimit = Math.floor(limit / 2);
    const suffix = `_${crypto
        .createHash('shake256', { outputLength: 1 })
        .update(`${tableOrEntityName}.${columnOrRelationshipName}`, 'utf8')
        .digest('hex')}`;
    let formattedName = noSnakeCase ? tableOrEntityName : hibernateSnakeCase(tableOrEntityName);
    formattedName = formattedName.substring(0, halfLimit - separator.length);
    let otherFormattedName = noSnakeCase ? columnOrRelationshipName : hibernateSnakeCase(columnOrRelationshipName);
    otherFormattedName = otherFormattedName.substring(0, limit - formattedName.length - separator.length - prefix.length - suffix.length);
    return `${prefix}${formattedName}${separator}${otherFormattedName}${suffix}`;
}
export function calculateDbName(tableOrEntityName, columnOrRelationshipName, { prodDatabaseType, noSnakeCase = false, prefix = '', suffix = '', skipCheckLengthOfIdentifier = false } = {}) {
    const separator = '__';
    const convertCase = noSnakeCase ? str => str : hibernateSnakeCase;
    const constraintName = `${prefix}${convertCase(tableOrEntityName)}${separator}${convertCase(columnOrRelationshipName)}${suffix}`;
    const { name, constraintNameMaxLength } = (prodDatabaseType && databaseData[prodDatabaseType]) || {};
    if (constraintNameMaxLength && constraintName.length > constraintNameMaxLength && !skipCheckLengthOfIdentifier) {
        return {
            warning: `The generated constraint name "${constraintName}" is too long for ${name} (which has a ${constraintNameMaxLength} character limit). It will be truncated!`,
            value: `${calculateDbNameWithLimit(tableOrEntityName, columnOrRelationshipName, constraintNameMaxLength - suffix.length, {
                separator,
                noSnakeCase,
                prefix,
            })}${suffix}`,
        };
    }
    return { value: constraintName };
}
export function getFKConstraintName(tableOrEntityName, columnOrRelationshipName, { prodDatabaseType, noSnakeCase, skipCheckLengthOfIdentifier } = {}) {
    return calculateDbName(tableOrEntityName, columnOrRelationshipName, {
        prodDatabaseType,
        noSnakeCase,
        prefix: 'fk_',
        suffix: '_id',
        skipCheckLengthOfIdentifier,
    });
}
export function getJoinTableName(entityName, relationshipName, { prodDatabaseType, skipCheckLengthOfIdentifier } = {}) {
    const separator = '__';
    const prefix = 'rel_';
    const joinTableName = `${prefix}${hibernateSnakeCase(entityName)}${separator}${hibernateSnakeCase(relationshipName)}`;
    const { name, tableNameMaxLength } = (prodDatabaseType && databaseData[prodDatabaseType]) || {};
    if (tableNameMaxLength && joinTableName.length > tableNameMaxLength && !skipCheckLengthOfIdentifier) {
        return {
            warning: `The generated join table "${joinTableName}" is too long for ${name} (which has a ${tableNameMaxLength} character limit). It will be truncated!`,
            value: calculateDbNameWithLimit(entityName, relationshipName, tableNameMaxLength, { prefix, separator }),
        };
    }
    return { value: joinTableName };
}
export function getUXConstraintName(entityName, columnName, { prodDatabaseType, noSnakeCase } = {}) {
    return calculateDbName(entityName, columnName, { prodDatabaseType, noSnakeCase, prefix: 'ux_' });
}
