 import { Injectable } from '@nestjs/common';
  import { SelectQueryBuilder } from 'typeorm';
  import {
    FilterCondition,
    FilterEngineOptions,
    FilterEngineResult,
    SortOption,
  } from './interfaces/filter.interface';
  import { PAGINATION_CONFIG } from '../../common/config/PaginationConfig';

  /**
   * 동적 필터링, 정렬, 페이지네이션을 제공하는 공통 엔진
   *
   * @export
   * @class FilterEngineService
   */
  @Injectable()
  export class FilterEngineService {
    /**
     * QueryBuilder에 필터 조건 적용
     *
     * @template T
     * @param {SelectQueryBuilder<T>} queryBuilder
     * @param {FilterCondition[]} filters
     * @returns {SelectQueryBuilder<T>}
     */
    applyFilters<T>(
      queryBuilder: SelectQueryBuilder<T>,
      filters: FilterCondition[],
    ): SelectQueryBuilder<T> {
      if (!filters || filters.length === 0) {
        return queryBuilder; // 필터 없으면 그대로 반환
      }

      filters.forEach((filter, index) => {
        const { field, operator, value } = filter;
        const paramName = `param_${index}`;

        switch (operator) { // 파라미터 바인딩
          case 'eq':
            queryBuilder.andWhere(`${field} = :${paramName}`, { [paramName]: value });
            break;

          case 'ne':
            queryBuilder.andWhere(`${field} != :${paramName}`, { [paramName]: value });
            break;

          case 'gt':
            queryBuilder.andWhere(`${field} > :${paramName}`, { [paramName]: value });
            break;

          case 'gte':
            queryBuilder.andWhere(`${field} >= :${paramName}`, { [paramName]: value });
            break;

          case 'lt':
            queryBuilder.andWhere(`${field} < :${paramName}`, { [paramName]: value });
            break;

          case 'lte':
            queryBuilder.andWhere(`${field} <= :${paramName}`, { [paramName]: value });
            break;

          case 'like':
            queryBuilder.andWhere(`${field} LIKE :${paramName}`, {
              [paramName]: `%${value}%`,
            });
            break;
            
          case 'in': 
            queryBuilder.andWhere(`${field} IN (:...${paramName})`, {
              [paramName]: value,
            });
            break;

          case 'between':
            if (Array.isArray(value) && value.length === 2) {
              queryBuilder.andWhere(`${field} BETWEEN :${paramName}_min AND :${paramName}_max`, {
                [`${paramName}_min`]: value[0],
                [`${paramName}_max`]: value[1],
              });
            }
            break;
        }
      });

      return queryBuilder;
    }

    /**
     * QueryBuilder에 정렬 옵션 적용
     *
     * @template T
     * @param {SelectQueryBuilder<T>} queryBuilder
     * @param {SortOption[]} sorts
     * @returns {SelectQueryBuilder<T>}
     */
    applySortOptions<T>(
      queryBuilder: SelectQueryBuilder<T>,
      sorts: SortOption[],
    ): SelectQueryBuilder<T> {
      if (!sorts || sorts.length === 0) {
        return queryBuilder;
      }

      sorts.forEach((sort, index) => {
        if (index === 0) {
          queryBuilder.orderBy(sort.field, sort.order);
        } else {
          queryBuilder.addOrderBy(sort.field, sort.order);
        }
      });

      return queryBuilder;
    }

    /**
     * QueryBuilder에 페이지네이션 적용
     *
     * @template T
     * @param {SelectQueryBuilder<T>} queryBuilder
     * @param {number} page
     * @param {number} limit
     * @returns {SelectQueryBuilder<T>}
     */
    applyPagination<T>(
      queryBuilder: SelectQueryBuilder<T>,
      page: number,
      limit: number,
    ): SelectQueryBuilder<T> {
      const skip = (page - 1) * limit;
      return queryBuilder.skip(skip).take(limit);
        // SQL: LIMIT 5 OFFSET 10
        // 10개 건너뛰고, 5개 가져오기 (11~15번째)  

    }

    /**
     * 필터링된 쿼리 실행 및 결과 반환 (전체실행 메인 함수)
     *
     * @async
     * @template T
     * @param {SelectQueryBuilder<T>} queryBuilder
     * @param {FilterEngineOptions} options
     * @returns {Promise<FilterEngineResult<T>>}
     */
    async executeFilteredQuery<T>(
      queryBuilder: SelectQueryBuilder<T>,
      options: FilterEngineOptions,
    ): Promise<FilterEngineResult<T>> {
      // 1. 필터 적용
      if (options.filters) {
        this.applyFilters(queryBuilder, options.filters);
      }

      // 2. 정렬 적용
      if (options.sorts) {
        this.applySortOptions(queryBuilder, options.sorts);
      }

      // 3. 전체 개수 조회 (페이지네이션 전)
      const total = await queryBuilder.getCount();

      // 4. 페이지네이션 적용 (기본값: PaginationConfig 사용)
      const page = options.pagination?.page ?? PAGINATION_CONFIG.LIMITS.DEFAULT_PAGE;
      const requestedLimit = options.pagination?.limit ?? PAGINATION_CONFIG.DEFAULTS.COW_LIST;
      // 최대값 제한 적용
      const limit = Math.min(
        Math.max(requestedLimit, PAGINATION_CONFIG.LIMITS.MIN),
        PAGINATION_CONFIG.LIMITS.MAX
      );
      this.applyPagination(queryBuilder, page, limit);

      // 5. 데이터 조회
      const data = await queryBuilder.getMany();

      // 6. 결과 구성
      const result: FilterEngineResult<T> = {
        data,
        total,
        page,
        limit,
        totalPages: Math.ceil(total / limit),
      };

      return result;
    }
  }