import { PaginationResponse } from 'src/core/response/domain/ok-response.interface';
import { BaseReadManager } from '../base-read.manager';
import { SelectQueryBuilder } from 'typeorm';
import { SpecificSearchFilter } from 'src/core/helpers/query/specific-search.helper';
import {
  getOrderBy,
  setQueryFilterDefault,
} from 'src/core/helpers/query/default-filter.helper';
import { Param } from '../../entities/base-filter.entity';
import { joinRelationHelper } from 'src/core/helpers/query/join-relations.helper';
import { STATUS } from 'src/core/strings/constants/base.constants';

export abstract class BaseIndexManager<Entity> extends BaseReadManager {
  protected result: PaginationResponse<Entity>;
  public filterParam: any;
  abstract get specificFilter(): Param[];

  setFilterParam(param: any): void {
    this.filterParam = param;
  }

  async process(): Promise<void> {
    const specificFilter = this.specificFilter;
    const { joinRelations, selectRelations, countRelations } = this.relations;

    if (joinRelations?.length)
      joinRelationHelper(joinRelations, this.tableName, this.queryBuilder);
    if (selectRelations?.length)
      joinRelationHelper(
        selectRelations,
        this.tableName,
        this.queryBuilder,
        'select',
      );
    if (countRelations?.length)
      joinRelationHelper(
        countRelations,
        this.tableName,
        this.queryBuilder,
        'count',
      );

    if (this.selects?.length) this.queryBuilder.select(this.selects);

    if (this.filterParam.statuses?.length > 0) {
      const data = this.filterParam.statuses.map((status) => {
        const statusData = status.includes("'")
          ? status.trim().replace(/'/g, "''").replace(/\s+/g, ' ')
          : status.trim().replace(/\s+/g, ' ');

        // jika searching status terdapat dalam enum, maka dia mencari specific data
        // ? karena jika tidak, ketika dia search "active" maka "inactive" juga ikut
        return `'${STATUS[statusData.toUpperCase()]}'`;
      });

      const exist = specificFilter.find((item) => item.isStatus);
      if (!exist) {
        specificFilter.push({
          cols: `${this.tableName}.status::text`,
          data: data,
        });
      }
    }

    new SpecificSearchFilter<Entity>(
      this.queryBuilder,
      this.tableName,
      specificFilter,
    ).getFilter();

    getOrderBy(this.filterParam, this.queryBuilder, this.tableName);
    this.setQueryFilter(this.queryBuilder);
    setQueryFilterDefault(this.queryBuilder, this.filterParam, this.tableName);

    this.result = await this.dataService.getIndex(
      this.queryBuilder,
      this.filterParam,
    );
  }

  abstract setQueryFilter(
    queryBuilder: SelectQueryBuilder<Entity>,
  ): SelectQueryBuilder<Entity>;

  getResult(): PaginationResponse<Entity> {
    return this.result;
  }
}
