import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import { BaseManager } from '../base.manager';
import { HttpStatus, NotFoundException } from '@nestjs/common';
import { ValidateRelationHelper } from 'src/core/helpers/validation/validate-relation.helper';
import { RecordLog } from 'src/modules/configuration/log/domain/entities/log.event';
import { OPERATION } from 'src/core/strings/constants/base.constants';

export abstract class BaseBatchDeleteManager<Entity> extends BaseManager {
  protected dataIds: string[];
  protected result: BatchResult;
  abstract get entityTarget(): any;

  setData(ids: string[]): void {
    this.dataIds = ids;
  }

  validateProcess(): Promise<void> {
    return;
  }

  prepareData(): Promise<void> {
    return;
  }

  async process(): Promise<void> {
    let totalFailed = 0;
    let totalSuccess = 0;
    const messages = [];

    for (const id of this.dataIds) {
      try {
        const entity = await this.dataService.getOneByOptions({
          where: {
            id: id,
          },
        });

        if (!entity) {
          throw new NotFoundException({
            statusCode: HttpStatus.NOT_FOUND,
            message: `Gagal! data dengan id ${id} tidak ditemukan`,
            error: 'Entity Not Found',
          });
        }

        await this.validateData(entity);
        await new ValidateRelationHelper(
          id,
          this.dataService,
          this.validateRelations,
          this.tableName,
        ).execute();

        await this.dataService.deleteById(
          this.queryRunner,
          this.entityTarget,
          id,
        );

        this.publishEvents(entity, entity);
        totalSuccess = totalSuccess + 1;
      } catch (error) {
        totalFailed = totalFailed + 1;
        messages.push(error.response?.message ?? error.message);
      }
    }

    this.result = {
      total_items: this.dataIds.length,
      total_failed: totalFailed,
      total_success: totalSuccess,
      messages: messages,
    };
  }

  abstract validateData(data: Entity): Promise<void>;
  abstract getResult(): BatchResult;

  async publishEvents(dataOld, dataNew) {
    this.eventBus.publish(
      new RecordLog({
        id: dataNew['id'],
        old: dataOld,
        data: dataNew,
        user: this.user,
        description: `${this.user.name} delete batch data ${this.tableName}`,
        module: this.tableName,
        op: OPERATION.DELETE,
      }),
    );

    if (!this.eventTopics.length) return;
    for (const topic of this.eventTopics) {
      this.eventBus.publishAll([
        new topic.topic({
          id: dataNew['id'],
          old: dataOld,
          data: dataNew,
          user: this.user,
          description: '',
          module: this.tableName,
          op: OPERATION.UPDATE,
        }),
      ]);
    }
  }
}
