import { CheckDuplicateHelper } from 'src/core/helpers/query/check-duplicate.helpers';
import { BaseManager } from '../base.manager';
import { RecordLog } from 'src/modules/configuration/log/domain/entities/log.event';
import { OPERATION } from 'src/core/strings/constants/base.constants';
import {
  columnUniques,
  validateRelations,
} from 'src/core/strings/constants/interface.constants';
import { MoveFilePathHelper } from 'src/core/helpers/path/move-file-path.helper';

export abstract class BaseCreateManager<Entity> extends BaseManager {
  protected result: Entity;
  protected duplicateColumn: string[];
  abstract get entityTarget(): any;
  abstract get uniqueColumns(): columnUniques[];

  setData(entity: Entity): void {
    this.data = entity;
  }

  get validateRelations(): validateRelations[] {
    return [];
  }

  async prepareData(): Promise<void> {
    Object.assign(this.data, {
      creator_id: this.user.id,
      creator_name: this.user.name,
      created_at: new Date().getTime(),
      updated_at: new Date().getTime(),
    });
  }

  async validateProcess(): Promise<void> {
    if (this.uniqueColumns.length) {
      await new CheckDuplicateHelper(
        this.dataService,
        this.tableName,
        this.uniqueColumns,
        this.data,
      ).execute();
    }
    return;
  }

  async process(): Promise<void> {
    const keys = Object.keys(this.data);
    if (
      (keys.includes('qr_image') || keys.includes('image_url')) &&
      (this.data['image_url']?.includes('tmp') ||
        this.data['qr_image']?.includes('tmp'))
    ) {
      await MoveFilePathHelper(this.data);
    }

    this.result = await this.dataService.create(
      this.queryRunner,
      this.entityTarget,
      this.data,
    );

    this.publishEvents();
  }

  async getResult(): Promise<Entity> {
    return await this.dataService.getOneByOptions({
      where: {
        id: this.result['id'],
      },
    });
  }

  async publishEvents() {
    this.eventBus?.publish(
      new RecordLog({
        id: this.result['id'],
        old: null,
        data: this.result,
        user: this.user,
        description: '',
        module: this.tableName,
        op: OPERATION.CREATE,
      }),
    );

    if (!this.eventTopics.length) return;
    for (const topic of this.eventTopics) {
      let data;
      if (!topic.data) {
        data = await this.dataService.getOneByOptions({
          where: {
            id: this.result['id'],
          },
          relations: topic.relations,
        });
      }

      this.eventBus.publishAll([
        new topic.topic({
          id: this.result['id'],
          old: null,
          data: data ?? topic.data,
          user: this.user,
          description: '',
          module: this.tableName,
          op: OPERATION.CREATE,
        }),
      ]);
    }
  }
}
