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

import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetMngEntity.mapSheetMngEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetMngHstEntity.mapSheetMngHstEntity;

import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngHstEntity;
import com.kamco.cd.kamcoback.scheduler.dto.MapSheetMngDto;
import com.kamco.cd.kamcoback.scheduler.dto.MapSheetMngDto.MngHstDto;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.CaseBuilder;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.StringExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import java.time.ZonedDateTime;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;

public class MapSheetMngFileJobRepositoryImpl extends QuerydslRepositorySupport
    implements MapSheetMngFileJobRepositoryCustom {

  private final JPAQueryFactory queryFactory;
  private final StringExpression NULL_STRING = Expressions.stringTemplate("cast(null as text)");

  @PersistenceContext private EntityManager em;

  public MapSheetMngFileJobRepositoryImpl(JPAQueryFactory queryFactory) {
    super(MapSheetMngHstEntity.class);
    this.queryFactory = queryFactory;
  }

  @Override
  public Page<MapSheetMngDto.MngDto> findMapSheetMngList(MapSheetMngDto.MngSearchReq searchReq) {

    Pageable pageable = searchReq.toPageable();
    BooleanBuilder whereBuilder = new BooleanBuilder();

    if (searchReq.getMngYyyy() != null) {
      whereBuilder.and(mapSheetMngEntity.mngYyyy.eq(searchReq.getMngYyyy()));
    }

    List<MapSheetMngDto.MngDto> foundContent =
        queryFactory
            .select(
                Projections.constructor(
                    MapSheetMngDto.MngDto.class,
                    Expressions.numberTemplate(
                        Integer.class,
                        "row_number() over(order by {0} desc)",
                        mapSheetMngEntity.createdDttm),
                    mapSheetMngEntity.mngYyyy,
                    mapSheetMngEntity.mngState,
                    mapSheetMngEntity.syncState,
                    mapSheetMngEntity.syncCheckState,
                    mapSheetMngHstEntity.count(),
                    new CaseBuilder()
                        .when(mapSheetMngHstEntity.syncState.eq("DONE"))
                        .then(1L)
                        .otherwise(0L)
                        .sum()
                        .as("syncStateDoneCnt"),
                    new CaseBuilder()
                        .when(mapSheetMngHstEntity.syncCheckState.eq("DONE"))
                        .then(1L)
                        .otherwise(0L)
                        .sum(),
                    new CaseBuilder()
                        .when(mapSheetMngHstEntity.dataState.eq("NOT"))
                        .then(1L)
                        .otherwise(0L)
                        .sum(),
                    new CaseBuilder()
                        .when(mapSheetMngHstEntity.dataState.eq("TYPEERROR"))
                        .then(1L)
                        .otherwise(0L)
                        .sum(),
                    new CaseBuilder()
                        .when(mapSheetMngHstEntity.dataState.eq("SIZEERROR"))
                        .then(1L)
                        .otherwise(0L)
                        .sum(),
                    mapSheetMngHstEntity.syncStrtDttm.min(),
                    mapSheetMngHstEntity.syncCheckEndDttm.max()))
            .from(mapSheetMngEntity)
            .leftJoin(mapSheetMngHstEntity)
            .on(mapSheetMngEntity.mngYyyy.eq(mapSheetMngHstEntity.mngYyyy))
            .where(whereBuilder)
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize())
            .orderBy(mapSheetMngEntity.createdDttm.desc())
            .groupBy(mapSheetMngEntity.mngYyyy)
            .fetch();

    Long countQuery =
        queryFactory
            .select(mapSheetMngEntity.mngYyyy.count())
            .from(mapSheetMngEntity)
            .where(whereBuilder)
            .fetchOne();

    return new PageImpl<>(foundContent, pageable, countQuery);
  }

  public void mngHstDataSyncStateUpdate(MapSheetMngDto.MngHstDto updateReq) {

    ZonedDateTime now = ZonedDateTime.now();

    if (updateReq.getDataState().equals("DONE")) {
      long updateCount =
          queryFactory
              .update(mapSheetMngHstEntity)
              .set(mapSheetMngHstEntity.dataState, updateReq.getDataState())
              .set(mapSheetMngHstEntity.dataStateDttm, now)
              .set(mapSheetMngHstEntity.syncState, updateReq.getSyncState())
              .set(mapSheetMngHstEntity.syncEndDttm, now)
              .set(mapSheetMngHstEntity.syncCheckState, "DONE")
              .set(mapSheetMngHstEntity.syncCheckStrtDttm, now)
              .set(mapSheetMngHstEntity.syncCheckEndDttm, now)
              .where(mapSheetMngHstEntity.hstUid.eq(updateReq.getHstUid()))
              .execute();
    } else {
      long updateCount =
          queryFactory
              .update(mapSheetMngHstEntity)
              .set(mapSheetMngHstEntity.dataState, updateReq.getDataState())
              .set(mapSheetMngHstEntity.dataStateDttm, now)
              .set(mapSheetMngHstEntity.syncState, updateReq.getSyncState())
              .set(mapSheetMngHstEntity.syncStrtDttm, now)
              .set(mapSheetMngHstEntity.syncEndDttm, now)
              .set(mapSheetMngHstEntity.syncCheckState, "PROCESSING")
              .set(mapSheetMngHstEntity.syncCheckStrtDttm, now)
              .set(mapSheetMngHstEntity.syncCheckEndDttm, now)
              .where(mapSheetMngHstEntity.hstUid.eq(updateReq.getHstUid()))
              .execute();
    }
  }

  @Override
  public List<MngHstDto> findTargetMapSheetFileList(long targetNum, int pageSize) {
    // Pageable pageable = searchReq.toPageable();

    List<MngHstDto> foundContent =
        queryFactory
            .select(
                Projections.constructor(
                    MngHstDto.class,
                    mapSheetMngHstEntity.hstUid,
                    mapSheetMngHstEntity.mngYyyy,
                    mapSheetMngHstEntity.mapSheetNum,
                    mapSheetMngHstEntity.refMapSheetNum,
                    mapSheetMngHstEntity.dataState,
                    mapSheetMngHstEntity.syncState,
                    mapSheetMngHstEntity.syncCheckState,
                    mapSheetMngHstEntity.syncStrtDttm,
                    mapSheetMngHstEntity.syncEndDttm,
                    mapSheetMngHstEntity.syncCheckStrtDttm,
                    mapSheetMngHstEntity.syncCheckEndDttm,
                    mapSheetMngEntity.mngPath))
            .from(mapSheetMngHstEntity)
            .join(mapSheetMngEntity)
            .on(mapSheetMngEntity.mngYyyy.eq(mapSheetMngHstEntity.mngYyyy))
            .where(
                mapSheetMngHstEntity.syncState.eq("NOTYET"),
                mapSheetMngHstEntity.hstUid.mod(10L).eq(targetNum))
            .limit(pageSize)
            .orderBy(mapSheetMngHstEntity.hstUid.asc())
            .fetch();

    return foundContent;
  }
}
