import { AbstractSqlPlatform } from '../../AbstractSqlPlatform.js';
import { SqliteNativeQueryBuilder } from './SqliteNativeQueryBuilder.js';
import { SqliteSchemaHelper } from './SqliteSchemaHelper.js';
import { SqliteExceptionConverter } from './SqliteExceptionConverter.js';
export class SqlitePlatform extends AbstractSqlPlatform {
  schemaHelper = new SqliteSchemaHelper(this);
  exceptionConverter = new SqliteExceptionConverter();
  /** @internal */
  createNativeQueryBuilder() {
    return new SqliteNativeQueryBuilder(this);
  }
  usesDefaultKeyword() {
    return false;
  }
  usesReturningStatement() {
    return true;
  }
  usesEnumCheckConstraints() {
    return true;
  }
  getCurrentTimestampSQL(length) {
    return `(strftime('%s', 'now') * 1000)`;
  }
  getDateTimeTypeDeclarationSQL(column) {
    return 'datetime';
  }
  getBeginTransactionSQL(options) {
    return ['begin'];
  }
  getEnumTypeDeclarationSQL(column) {
    if (column.items?.every(item => typeof item === 'string')) {
      return 'text';
    }
    /* v8 ignore next */
    return this.getTinyIntTypeDeclarationSQL(column);
  }
  getTinyIntTypeDeclarationSQL(column) {
    return this.getIntegerTypeDeclarationSQL(column);
  }
  getSmallIntTypeDeclarationSQL(column) {
    return this.getIntegerTypeDeclarationSQL(column);
  }
  getIntegerTypeDeclarationSQL(column) {
    return 'integer';
  }
  getFloatDeclarationSQL() {
    return 'real';
  }
  getBooleanTypeDeclarationSQL() {
    return 'integer';
  }
  getCharTypeDeclarationSQL(column) {
    return 'text';
  }
  getVarcharTypeDeclarationSQL(column) {
    return 'text';
  }
  normalizeColumnType(type, options) {
    const simpleType = this.extractSimpleType(type);
    if (['varchar', 'text'].includes(simpleType)) {
      return this.getVarcharTypeDeclarationSQL(options);
    }
    return simpleType;
  }
  convertsJsonAutomatically() {
    return false;
  }
  /**
   * This is used to narrow the value of Date properties as they will be stored as timestamps in sqlite.
   * We use this method to convert Dates to timestamps when computing the changeset, so we have the right
   * data type in the payload as well as in original entity data. Without that, we would end up with diffs
   * including all Date properties, as we would be comparing Date object with timestamp.
   */
  processDateProperty(value) {
    if (value instanceof Date) {
      return +value;
    }
    return value;
  }
  getIndexName(tableName, columns, type) {
    if (type === 'primary') {
      return this.getDefaultPrimaryName(tableName, columns);
    }
    return super.getIndexName(tableName, columns, type);
  }
  supportsDeferredUniqueConstraints() {
    return false;
  }
  /**
   * SQLite supports schemas via ATTACH DATABASE. Returns true when there are
   * attached databases configured.
   */
  supportsSchemas() {
    const attachDatabases = this.config.get('attachDatabases');
    return !!attachDatabases?.length;
  }
  getDefaultSchemaName() {
    // Return 'main' only when schema support is active (i.e., databases are attached)
    return this.supportsSchemas() ? 'main' : undefined;
  }
  getFullTextWhereClause() {
    return `:column: match :query`;
  }
  escape(value) {
    if (value == null) {
      return 'null';
    }
    if (typeof value === 'boolean') {
      return value ? 'true' : 'false';
    }
    if (typeof value === 'number' || typeof value === 'bigint') {
      return '' + value;
    }
    if (value instanceof Date) {
      return '' + +value;
    }
    if (Array.isArray(value)) {
      return value.map(v => this.escape(v)).join(', ');
    }
    if (Buffer.isBuffer(value)) {
      return `X'${value.toString('hex')}'`;
    }
    return `'${String(value).replace(/'/g, "''")}'`;
  }
  convertVersionValue(value, prop) {
    if (prop.runtimeType === 'Date') {
      const ts = +value;
      const str = new Date(ts)
        .toISOString()
        .replace('T', ' ')
        .replace(/\.\d{3}Z$/, '');
      return { $in: [ts, str] };
    }
    return value;
  }
  getJsonArrayElementPropertySQL(alias, property, _type) {
    return `json_extract(${this.quoteIdentifier(alias)}.value, '$.${this.quoteJsonKey(property)}')`;
  }
  quoteValue(value) {
    if (value instanceof Date) {
      return '' + +value;
    }
    return super.quoteValue(value);
  }
}
