package com.kamco.cd.kamcoback.postgres.repository.menu;

import static com.kamco.cd.kamcoback.postgres.entity.QMenuEntity.menuEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMenuMappEntity.menuMappEntity;

import com.kamco.cd.kamcoback.menu.dto.MenuDto.MenuWithRolesDto;
import com.kamco.cd.kamcoback.postgres.entity.MenuEntity;
import com.kamco.cd.kamcoback.postgres.entity.QMenuEntity;
import com.kamco.cd.kamcoback.postgres.entity.QMenuMappEntity;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

@Repository
@RequiredArgsConstructor
public class MenuRepositoryImpl implements MenuRepositoryCustom {

  private final JPAQueryFactory queryFactory;

  @Override
  public List<MenuEntity> getFindAll() {
    return queryFactory.selectFrom(menuEntity).where(menuEntity.deleted.isFalse()).fetch();
  }

  /**
   * 권한별 메뉴 목록
   *
   * @return
   */
  @Override
  public List<MenuEntity> getFindByRole(String role) {

    QMenuEntity child = new QMenuEntity("child");
    List<MenuEntity> content =
        queryFactory
            .selectDistinct(menuEntity)
            .from(menuEntity)
            .leftJoin(menuEntity.children, child)
            .fetchJoin()
            .leftJoin(menuMappEntity)
            .on(
                menuMappEntity
                    .roleCode
                    .eq(role)
                    .and(menuMappEntity.deleted.isFalse())
                    .and(
                        menuMappEntity.menuUid.eq(menuEntity).or(menuMappEntity.menuUid.eq(child))))
            .where(
                menuEntity.parent.isNull(),
                menuEntity.deleted.isFalse(),
                menuEntity.isUse.isTrue(),
                menuMappEntity.id.isNotNull())
            .orderBy(menuEntity.menuOrder.asc().nullsLast(), child.menuOrder.asc().nullsLast())
            .fetch();

    return content;
  }

  @Override
  public List<MenuWithRolesDto> getFindByMenuWithRoles() {
    QMenuEntity tm = menuEntity;
    QMenuMappEntity tmm = menuMappEntity;

    Expression<String> roleAgg =
        Expressions.stringTemplate("string_agg({0}, {1})", tmm.roleCode, Expressions.constant(","));

    List<MenuWithRolesDto> content =
        queryFactory
            .select(
                Projections.constructor(
                    MenuWithRolesDto.class,
                    tm.menuUid,
                    tm.menuNm,
                    tm.menuUrl,
                    tm.menuApiUri,
                    roleAgg))
            .from(tm)
            .leftJoin(tmm)
            .on(tmm.menuUid.eq(tm).and(tmm.deleted.isFalse()))
            .where(tm.deleted.isFalse())
            .groupBy(tm.menuUid, tm.menuNm, tm.menuUrl, tm.menuApiUri)
            .fetch();
    return content;
  }
}
