import { LockMode, RawQueryFragment, Utils } from '@mikro-orm/core';
import { NativeQueryBuilder } from '../../query/NativeQueryBuilder.js';
/** @internal */
export class MySqlNativeQueryBuilder extends NativeQueryBuilder {
  compileInsert() {
    if (!this.options.data) {
      throw new Error('No data provided');
    }
    this.parts.push('insert');
    if (this.options.onConflict?.ignore) {
      this.parts.push('ignore');
    }
    this.addHintComment();
    this.parts.push(`into ${this.getTableName()}`);
    if (Object.keys(this.options.data).length === 0) {
      this.parts.push('default values');
      return;
    }
    const parts = this.processInsertData();
    this.parts.push(parts.join(', '));
  }
  addLockClause() {
    if (!this.options.lockMode) {
      return;
    }
    const map = {
      [LockMode.PESSIMISTIC_READ]: 'lock in share mode',
      [LockMode.PESSIMISTIC_WRITE]: 'for update',
      [LockMode.PESSIMISTIC_PARTIAL_WRITE]: 'for update skip locked',
      [LockMode.PESSIMISTIC_WRITE_OR_FAIL]: 'for update nowait',
      [LockMode.PESSIMISTIC_PARTIAL_READ]: 'lock in share mode skip locked',
      [LockMode.PESSIMISTIC_READ_OR_FAIL]: 'lock in share mode nowait',
    };
    if (this.options.lockMode !== LockMode.OPTIMISTIC) {
      this.parts.push(map[this.options.lockMode]);
    }
  }
  addOnConflictClause() {
    const clause = this.options.onConflict;
    if (!clause || clause.ignore) {
      return;
    }
    if (clause.merge) {
      this.parts.push('on duplicate key update');
      if (Utils.isObject(clause.merge)) {
        const fields = Object.keys(clause.merge).map(field => {
          this.params.push(clause.merge[field]);
          return `${this.quote(field)} = ?`;
        });
        this.parts.push(fields.join(', '));
      } else if (clause.merge.length === 0) {
        const dataAsArray = Utils.asArray(this.options.data);
        const keys = Object.keys(dataAsArray[0]);
        this.parts.push(keys.map(key => `${this.quote(key)} = values(${this.quote(key)})`).join(', '));
      } else {
        const fields = clause.merge.map(key => `${this.quote(key)} = values(${this.quote(key)})`);
        this.parts.push(fields.join(', '));
      }
      if (clause.where) {
        this.parts.push(`where ${clause.where.sql}`);
        this.params.push(...clause.where.params);
      }
      return;
    }
    this.parts.push('on conflict');
    if (clause.fields instanceof RawQueryFragment) {
      this.parts.push(clause.fields.sql);
      this.params.push(...clause.fields.params);
    } else if (clause.fields.length > 0) {
      const fields = clause.fields.map(field => this.quote(field));
      this.parts.push(`(${fields.join(', ')})`);
    }
  }
}
