import { EntityRepository } from '../entity/EntityRepository.js';
import { type NamingStrategy } from '../naming-strategy/NamingStrategy.js';
import type {
  Constructor,
  EntityMetadata,
  EntityProperty,
  IPrimaryKey,
  ISchemaGenerator,
  PopulateOptions,
  Primary,
  SimpleColumnMeta,
  FilterQuery,
  EntityValue,
  EntityKey,
} from '../typings.js';
import { ExceptionConverter } from './ExceptionConverter.js';
import type { EntityManager } from '../EntityManager.js';
import type { Configuration } from '../utils/Configuration.js';
import type { IDatabaseDriver } from '../drivers/IDatabaseDriver.js';
import { Type } from '../types/index.js';
import type { MikroORM } from '../MikroORM.js';
import type { TransformContext } from '../types/Type.js';
import { Raw } from '../utils/RawQueryFragment.js';
/** Symbol used to tag cloned embeddable data for JSON serialization handling. */
export declare const JsonProperty: unique symbol;
/** Abstract base class providing database-specific behavior and SQL dialect differences. */
export declare abstract class Platform {
  protected readonly exceptionConverter: ExceptionConverter;
  protected config: Configuration;
  protected namingStrategy: NamingStrategy;
  protected timezone?: string;
  /** Whether this driver uses pivot tables for M:N relations (SQL drivers do, MongoDB does not). */
  usesPivotTable(): boolean;
  /** Whether this driver supports database transactions. */
  supportsTransactions(): boolean;
  /** Whether the driver wraps operations in implicit transactions by default. */
  usesImplicitTransactions(): boolean;
  /** Returns the default naming strategy constructor for this platform. */
  getNamingStrategy(): {
    new (): NamingStrategy;
  };
  /** Whether the driver supports RETURNING clause (e.g. PostgreSQL). */
  usesReturningStatement(): boolean;
  /** Whether the driver supports OUTPUT clause (e.g. MSSQL). */
  usesOutputStatement(): boolean;
  /** Whether DELETE statements require explicit CASCADE keyword. */
  usesCascadeStatement(): boolean;
  /** for postgres native enums */
  supportsNativeEnums(): boolean;
  /** for postgres text enums (default) */
  usesEnumCheckConstraints(): boolean;
  /** Whether this platform supports materialized views. */
  supportsMaterializedViews(): boolean;
  /** Returns the schema helper instance for this platform, or undefined if not supported. */
  getSchemaHelper(): unknown;
  /** Whether the platform automatically creates indexes on foreign key columns. */
  indexForeignKeys(): boolean;
  /**
   * Whether or not the driver supports retuning list of created PKs back when multi-inserting
   */
  usesBatchInserts(): boolean;
  /**
   * Whether or not the driver supports updating many records at once
   */
  usesBatchUpdates(): boolean;
  /** Whether the platform supports the DEFAULT keyword in INSERT statements. */
  usesDefaultKeyword(): boolean;
  /**
   * Normalizes primary key wrapper to scalar value (e.g. mongodb's ObjectId to string)
   */
  normalizePrimaryKey<T extends number | string = number | string>(data: Primary<T> | IPrimaryKey): T;
  /**
   * Converts scalar primary key representation to native driver wrapper (e.g. string to mongodb's ObjectId)
   */
  denormalizePrimaryKey(data: IPrimaryKey): IPrimaryKey;
  /**
   * Returns the SQL specific for the platform to get the current timestamp
   */
  getCurrentTimestampSQL(length?: number): string;
  /** Returns the SQL type declaration for datetime columns. */
  getDateTimeTypeDeclarationSQL(column: { length?: number }): string;
  /** Returns the default fractional seconds precision for datetime columns. */
  getDefaultDateTimeLength(): number;
  /** Returns the default length for varchar columns. */
  getDefaultVarcharLength(): number;
  /** Returns the default length for char columns. */
  getDefaultCharLength(): number;
  /** Returns the SQL type declaration for date columns. */
  getDateTypeDeclarationSQL(length?: number): string;
  /** Returns the SQL type declaration for time columns. */
  getTimeTypeDeclarationSQL(length?: number): string;
  /** Returns the SQL operator used for regular expression matching. */
  getRegExpOperator(val?: unknown, flags?: string): string;
  /** Builds the SQL clause and parameters for a regular expression condition. */
  mapRegExpCondition(
    mappedKey: string,
    value: {
      $re: string;
      $flags?: string;
    },
  ): {
    sql: string;
    params: unknown[];
  };
  /** Converts a JavaScript RegExp into a platform-specific regex representation. */
  getRegExpValue(val: RegExp): {
    $re: string;
    $flags?: string;
  };
  /** Whether the given operator is allowed at the top level of a query condition. */
  isAllowedTopLevelOperator(operator: string): boolean;
  /** Converts a version field value for comparison in optimistic locking queries. */
  convertVersionValue(
    value: Date | number,
    prop: EntityProperty,
  ):
    | Date
    | string
    | number
    | {
        $in: (string | number)[];
      };
  /** Returns the default fractional seconds precision for version timestamp columns. */
  getDefaultVersionLength(): number;
  /** Whether the platform supports tuple comparison in WHERE clauses. */
  allowsComparingTuples(): boolean;
  /** Whether the given property maps to a bigint database column. */
  isBigIntProperty(prop: EntityProperty): boolean;
  /** Returns the default schema name for this platform (e.g. "public" for PostgreSQL). */
  getDefaultSchemaName(): string | undefined;
  /** Returns the SQL type declaration for boolean columns. */
  getBooleanTypeDeclarationSQL(): string;
  /** Returns the SQL type declaration for integer columns. */
  getIntegerTypeDeclarationSQL(column: { length?: number; unsigned?: boolean; autoincrement?: boolean }): string;
  getSmallIntTypeDeclarationSQL(column: { length?: number; unsigned?: boolean; autoincrement?: boolean }): string;
  getMediumIntTypeDeclarationSQL(column: { length?: number; unsigned?: boolean; autoincrement?: boolean }): string;
  getTinyIntTypeDeclarationSQL(column: { length?: number; unsigned?: boolean; autoincrement?: boolean }): string;
  getBigIntTypeDeclarationSQL(column: { length?: number; unsigned?: boolean; autoincrement?: boolean }): string;
  getCharTypeDeclarationSQL(column: { length?: number }): string;
  getVarcharTypeDeclarationSQL(column: { length?: number }): string;
  getIntervalTypeDeclarationSQL(column: { length?: number }): string;
  getTextTypeDeclarationSQL(_column: { length?: number }): string;
  getEnumTypeDeclarationSQL(column: {
    items?: unknown[];
    fieldNames: string[];
    length?: number;
    unsigned?: boolean;
    autoincrement?: boolean;
  }): string;
  getFloatDeclarationSQL(): string;
  getDoubleDeclarationSQL(): string;
  getDecimalTypeDeclarationSQL(column: { precision?: number; scale?: number }): string;
  getUuidTypeDeclarationSQL(column: { length?: number }): string;
  /** Extracts the base type name from a full SQL type declaration (e.g. "varchar(255)" -> "varchar"). */
  extractSimpleType(type: string): string;
  /**
   * This should be used only to compare types, it can strip some information like the length.
   */
  normalizeColumnType(
    type: string,
    options: {
      length?: number;
      precision?: number;
      scale?: number;
    },
  ): string;
  /** Returns the mapped Type instance for a given SQL/runtime type string. */
  getMappedType(type: string): Type<unknown>;
  /** Returns the default mapped Type for a given type string when no custom mapping is configured. */
  getDefaultMappedType(type: string): Type<unknown>;
  /** Whether the platform supports multiple cascade paths to the same table. */
  supportsMultipleCascadePaths(): boolean;
  /**
   * Returns true if the platform supports ON UPDATE foreign key rules.
   * Oracle doesn't support ON UPDATE rules.
   */
  supportsOnUpdate(): boolean;
  /** Whether the connection supports executing multiple SQL statements in a single call. */
  supportsMultipleStatements(): boolean;
  /** Whether the platform supports the UNION WHERE optimization for multi-branch queries. */
  supportsUnionWhere(): boolean;
  /** Returns the SQL type declaration used for array storage. */
  getArrayDeclarationSQL(): string;
  /** Serializes a string array into its database storage format. */
  marshallArray(values: string[]): string;
  /** Deserializes a database-stored array string back into a string array. */
  unmarshallArray(value: string): string[];
  getBlobDeclarationSQL(): string;
  getJsonDeclarationSQL(): string;
  getSearchJsonPropertySQL(path: string, type: string, aliased: boolean): string | Raw;
  getSearchJsonPropertyKey(path: string[], type: string, aliased: boolean, value?: unknown): string | Raw;
  processJsonCondition<T extends object>(
    o: FilterQuery<T>,
    value: EntityValue<T>,
    path: EntityKey<T>[],
    alias: boolean,
  ): FilterQuery<T>;
  protected getJsonValueType(value: unknown): string;
  getJsonIndexDefinition(index: { columnNames: string[] }): string[];
  getFullTextWhereClause(prop: EntityProperty): string;
  supportsCreatingFullTextIndex(): boolean;
  getFullTextIndexExpression(
    indexName: string,
    schemaName: string | undefined,
    tableName: string,
    columns: SimpleColumnMeta[],
  ): string;
  /** Whether the driver automatically parses JSON columns into JS objects. */
  convertsJsonAutomatically(): boolean;
  /** Converts a JS value to its JSON database representation (typically JSON.stringify). */
  convertJsonToDatabaseValue(value: unknown, context?: TransformContext): unknown;
  /** Converts a database JSON value to its JS representation. */
  convertJsonToJSValue(value: unknown, context?: TransformContext): unknown;
  convertDateToJSValue(value: string | Date): string;
  convertIntervalToJSValue(value: string): unknown;
  convertIntervalToDatabaseValue(value: unknown): unknown;
  usesAsKeyword(): boolean;
  /**
   * Determines how UUID values are compared in the change set tracking.
   * Return `'string'` for inline string comparison (fast), or `'any'` for deep comparison via type methods.
   */
  compareUuids(): string;
  convertUuidToJSValue(value: unknown): unknown;
  convertUuidToDatabaseValue(value: unknown): unknown;
  /** Parses a string or numeric value into a Date object. */
  parseDate(value: string | number): Date;
  /** Returns the default EntityRepository class used by this platform. */
  getRepositoryClass<T extends object>(): Constructor<EntityRepository<T>>;
  /** Returns the default character set for this platform. */
  getDefaultCharset(): string;
  /** Returns the exception converter for translating native errors to driver exceptions. */
  getExceptionConverter(): ExceptionConverter;
  /**
   * Allows registering extensions of the driver automatically (e.g. `SchemaGenerator` extension in SQL drivers).
   */
  lookupExtensions(orm: MikroORM): void;
  /** @internal */
  init(orm: MikroORM): void;
  /** Retrieves a registered extension (e.g. SchemaGenerator, Migrator), throwing if not found. */
  getExtension<T>(extensionName: string, extensionKey: string, moduleName: string, em: EntityManager): T;
  getSchemaGenerator(driver: IDatabaseDriver, em?: EntityManager): ISchemaGenerator;
  /** Processes a date value before persisting, applying timezone or format conversions. */
  processDateProperty(value: unknown): string | number | Date;
  /** Wraps a table or column identifier with the platform-specific quote character. */
  quoteIdentifier(
    id:
      | string
      | {
          toString: () => string;
        },
    quote?: string,
  ): string;
  /** Quotes a literal value for safe embedding in SQL. */
  quoteValue(value: any): string;
  escape(value: any): string;
  /** Replaces `?` placeholders in SQL with quoted parameter values. */
  formatQuery(sql: string, params: readonly any[]): string;
  /** Deep-clones embeddable data and tags it for JSON serialization. */
  cloneEmbeddable<T>(data: T): T;
  /** Initializes the platform with the ORM configuration. */
  setConfig(config: Configuration): void;
  /** Returns the current ORM configuration. */
  getConfig(): Configuration;
  /** Returns the configured timezone, or undefined if not set. */
  getTimezone(): string | undefined;
  /** Whether the given property represents a numeric database column. */
  isNumericProperty(prop: EntityProperty, ignoreCustomType?: boolean): boolean;
  /** Whether the given mapped type represents a numeric column. */
  isNumericColumn(mappedType: Type<unknown>): boolean;
  /** Whether the platform supports unsigned integer columns. */
  supportsUnsigned(): boolean;
  /**
   * Returns the default name of index for the given columns
   */
  getIndexName(
    tableName: string,
    columns: string[],
    type: 'index' | 'unique' | 'foreign' | 'primary' | 'sequence',
  ): string;
  /** Returns the default primary key constraint name. */
  getDefaultPrimaryName(tableName: string, columns: string[]): string;
  /** Whether the platform supports custom names for primary key constraints. */
  supportsCustomPrimaryKeyNames(): boolean;
  /** Whether the given property key is included in the populate hint. */
  isPopulated<T>(key: string, populate: readonly PopulateOptions<T>[] | boolean): boolean;
  /** Whether the given property should be included as a column in the SELECT query. */
  shouldHaveColumn<T>(
    prop: EntityProperty<T>,
    populate: readonly PopulateOptions<T>[] | boolean,
    exclude?: string[],
    includeFormulas?: boolean,
    ignoreInlineEmbeddables?: boolean,
  ): boolean;
  /**
   * Currently not supported due to how knex does complex sqlite diffing (always based on current schema)
   */
  /** Whether the platform supports generating down migrations. */
  supportsDownMigrations(): boolean;
  /** Whether the platform supports deferred unique constraints. */
  supportsDeferredUniqueConstraints(): boolean;
  /** Platform-specific validation of entity metadata. */
  validateMetadata(meta: EntityMetadata): void;
  /**
   * Generates a custom order by statement given a set of in order values, eg.
   * ORDER BY (CASE WHEN priority = 'low' THEN 1 WHEN priority = 'medium' THEN 2 ELSE NULL END)
   */
  generateCustomOrder(escapedColumn: string, values: unknown[]): void;
  /**
   * Returns default client url for given driver (e.g. mongodb://127.0.0.1:27017 for mongodb)
   */
  getDefaultClientUrl(): string;
  /**
   * @internal
   */
  castColumn(prop?: { columnTypes?: string[] }): string;
  /**
   * @internal
   */
  castJsonValue(prop?: { columnTypes?: string[] }): string;
  /**
   * @internal
   */
  clone(): this;
}
