package com.icomsys.main_vm.db.jpa.repo.system.dsl;

import com.icomsys.main_vm.biz.common.login.res.OprmngCodeRes;
import com.icomsys.main_vm.biz.common.login.res.UserVo;
import com.icomsys.main_vm.biz.common.system.vo.SystemServiceGroupReq;
import com.icomsys.main_vm.biz.common.system.vo.SystemServiceGroupRes;
import com.icomsys.main_vm.biz.common.system.vo.SystemServiceGroupViewVo;
import com.icomsys.main_vm.common.code.enumresource.RoleResource;
import com.icomsys.main_vm.db.jpa.entity.system.*;
import com.querydsl.core.QueryResults;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.querydsl.jpa.sql.JPASQLQuery;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;

import java.util.ArrayList;
import java.util.List;

@Aspect
@Slf4j
@RequiredArgsConstructor
public class TbServiceGrouopRepoDslImpl implements TbServiceGrouopRepoDsl {


    private final JPAQueryFactory queryFactory;
    private final QTbIcsCustInfo qTbIcsCustInfo = QTbIcsCustInfo.tbIcsCustInfo;
    private final QTbServiceGrouop qTbServiceGrouop = QTbServiceGrouop.tbServiceGrouop;
    private final QTbIcsOprMngInfo qTbIcsOprMngInfo = QTbIcsOprMngInfo.tbIcsOprMngInfo;
    private final QTbUserCust qTbUserCust = QTbUserCust.tbUserCust;
    private final QTbCustPolicy qTbCustPolicy = QTbCustPolicy.tbCustPolicy;
    private final QTbServiceGroupPolicy qTbServiceGroupPolicy = QTbServiceGroupPolicy.tbServiceGroupPolicy;
    private final QTbUserAuthGroup qTbUserAuthGroup = QTbUserAuthGroup.tbUserAuthGroup;

    @Override
    public QueryResults<SystemServiceGroupRes> ServiceGroupList(SystemServiceGroupReq dto) {
        QueryResults<SystemServiceGroupRes> result =
                queryFactory.select(
                                Projections.fields(
                                        SystemServiceGroupRes.class,
                                        qTbServiceGrouop.custCode,
                                        qTbIcsCustInfo.custName,
                                        qTbServiceGrouop.serviceGroup,
                                        qTbServiceGrouop.serviceGroupName,
                                        qTbServiceGrouop.serviceType,
                                        qTbServiceGrouop.useYn,
                                        qTbServiceGrouop.registDate
                                )
                        ).from(qTbServiceGrouop)
                        .innerJoin(qTbIcsCustInfo).on(qTbIcsCustInfo.custCode.eq(qTbServiceGrouop.custCode))
                        .where(qTbServiceGrouopeq(dto)
                                , QTbserviceGroupNameeq(dto)
                                , qTbServiceGrouop.serviceType.eq("M")
                        )
                        .limit(dto.getSize())
                        .offset(dto.getPage() * dto.getSize())
                        .orderBy(qTbServiceGrouop.registDate.asc())
                        .fetchResults();
        return result;
    }

    private BooleanExpression qTbServiceGrouopeq(SystemServiceGroupReq dto) {
        return dto.getServiceGroup().equals("ALL") ?
                null : qTbServiceGrouop.serviceGroup.eq(dto.getServiceGroup());
    }

    private BooleanExpression QTbserviceGroupNameeq(SystemServiceGroupReq dto) {
        if (dto.getCodeText() == null || dto.getCodeText().equals("")) {
            return null;
        } else {
            return qTbServiceGrouop.serviceGroupName.upper().contains(dto.getCodeText().toUpperCase());
        }
    }

    @Override
    public List<OprmngCodeRes> getOprmngCode(UserVo dto, String serviceType, String menuval) {
        List<OprmngCodeRes> result = new ArrayList<>();
        //시스템어드민은다보여줌.
        if (dto.getRoleVal().equals(RoleResource.SYSTEMADMIN.getName())) {
            return result = queryFactory.select(
                            Projections.fields(
                                    OprmngCodeRes.class,
                                    qTbServiceGrouop.custCode,
                                    qTbServiceGrouop.serviceGroup,
                                    qTbServiceGrouop.serviceGroupName,
                                    qTbServiceGrouop.serviceGroupUpper
                                    )
                    )
                    .from(qTbServiceGrouop)
                    .where(serviceTypeEq(serviceType), qTbServiceGrouop.useYn.eq("Y"))
//                    .innerJoin(qTbIcsOprMngInfo).on(qTbServiceGrouop.serviceGroup.eq(qTbIcsOprMngInfo.serviceGroup))
                    .groupBy(qTbServiceGrouop.custCode,
                            qTbServiceGrouop.serviceGroup,
                            qTbServiceGrouop.serviceGroupName,
                            qTbServiceGrouop.serviceGroupUpper)
                    .fetch();
        } else {
            if (menuval == null || menuval.equals("")) {
                //메뉴발이 없는 유저어드민
                if (dto.getRoleVal().equals(RoleResource.USERADMIN.getName())) {
                    return result = queryFactory.select(
                                    Projections.fields(
                                            OprmngCodeRes.class,
                                            qTbServiceGrouop.custCode,
                                            qTbServiceGrouop.serviceGroup,
                                            qTbServiceGrouop.serviceGroupName,
                                            qTbServiceGrouop.serviceGroupUpper
                                    )
                            )
                            .from(qTbServiceGrouop)
                            .where(serviceTypeEq(serviceType), qTbServiceGrouop.serviceGroupUpper.eq(dto.getLastUseServiceGroup()), qTbServiceGrouop.useYn.eq("Y"))
//                    .innerJoin(qTbIcsOprMngInfo).on(qTbServiceGrouop.serviceGroup.eq(qTbIcsOprMngInfo.serviceGroup))
                            .groupBy(qTbServiceGrouop.custCode,
                                    qTbServiceGrouop.serviceGroup,
                                    qTbServiceGrouop.serviceGroupName,
                                    qTbServiceGrouop.serviceGroupUpper)
                            .fetch();
                }
                //메뉴발이 없는 유저
                else {
                    return result = queryFactory.select(
                                    Projections.fields(
                                            OprmngCodeRes.class,
                                            qTbServiceGrouop.custCode,
                                            qTbServiceGrouop.serviceGroup,
                                            qTbServiceGrouop.serviceGroupName,
                                            qTbServiceGrouop.serviceGroupUpper
                                    )
                            )
                            .from(qTbUserCust)
                            //내가사용할 수 있는 UserCust의 서비스그룹
                            .innerJoin(qTbServiceGrouop).on(qTbUserCust.serviceGroup.eq(qTbServiceGrouop.serviceGroup))
                            //서비스그룹으로 공통코드 opr 값 뽑기
//                    .innerJoin(qTbIcsOprMngInfo).on(qTbServiceGrouop.serviceGroup.eq(qTbIcsOprMngInfo.serviceGroup))
                            //뽑은 opr로 공통코드 데이터뽑기
                            .where(qTbUserCust.userSeq.eq(dto.getUserSeq())
                                    //현재 사용중인 ServiceTypeM = lastUseServiceGroup로
                                    , qTbServiceGrouop.serviceGroupUpper.eq(dto.getLastUseServiceGroup())
                                    , serviceTypeEq(serviceType)
                                    , qTbServiceGrouop.useYn.eq("Y")
                            )
                            .groupBy(qTbServiceGrouop.custCode,
                                    qTbServiceGrouop.serviceGroup,
                                    qTbServiceGrouop.serviceGroupName,
                                    qTbServiceGrouop.serviceGroupUpper)
                            .fetch();
                }
            } else {

                //메뉴발이 있는 유저어드민
                //유저어드민은 권한 상관 없이 상위서비스그룹의 메뉴들을 다 볼수 있어야함.
                if (dto.getRoleVal().equals(RoleResource.USERADMIN.getName())) {
                    result = queryFactory.select(
                                    Projections.fields(
                                            OprmngCodeRes.class,
                                            qTbServiceGrouop.custCode,
                                            qTbServiceGrouop.serviceGroup,
                                            qTbServiceGrouop.serviceGroupName,
                                            qTbServiceGrouop.serviceGroupUpper
                                    )
                            )
                            .from(qTbServiceGrouop)
//                            .innerJoin(qTbServiceGroupPolicy).on(qTbServiceGrouop.serviceGroup.eq(qTbServiceGroupPolicy.serviceGroup))
                            .where(qTbServiceGrouop.serviceGroupUpper.eq(dto.getLastUseServiceGroup())
                                    , serviceTypeEq(serviceType)
//                                    , qTbServiceGroupPolicy.policyVal.like(menuval + "%")
                            )
                            .groupBy(qTbServiceGrouop.custCode,
                                    qTbServiceGrouop.serviceGroup,
                                    qTbServiceGrouop.serviceGroupName,
                                    qTbServiceGrouop.serviceGroupUpper)
                            .fetch();

                    return result;
                }
                //메뉴발이 있는 유저
                else {

                    result = queryFactory.select(
                                    Projections.fields(
                                            OprmngCodeRes.class,
                                            qTbServiceGrouop.custCode,
                                            qTbServiceGrouop.serviceGroup,
                                            qTbServiceGrouop.serviceGroupName,
                                            qTbServiceGrouop.serviceGroupUpper
                                    )
                            )
                            .from(qTbUserAuthGroup)
                            .innerJoin(qTbServiceGroupPolicy).on(qTbUserAuthGroup.authGroupSeq.eq(qTbServiceGroupPolicy.authGroupSeq))
                            .innerJoin(qTbServiceGrouop).on(qTbServiceGroupPolicy.serviceGroup.eq(qTbServiceGrouop.serviceGroup))
                            .where(qTbUserAuthGroup.userSeq.eq(dto.getUserSeq()),
                                    qTbServiceGroupPolicy.policyVal.like(menuval + "%")
//                                  , qTbServiceGrouop.serviceType.eq("S")
                                    , serviceTypeEq(serviceType),
                                    qTbServiceGrouop.useYn.eq("Y"))
                            .groupBy(qTbServiceGrouop.custCode,
                                    qTbServiceGrouop.serviceGroup,
                                    qTbServiceGrouop.serviceGroupName,
                                    qTbServiceGrouop.serviceGroupUpper)
                            .fetch();

                    return result;
                }
            }
        }
    }

    private BooleanExpression serviceTypeEq(String serviceType) {
        if (serviceType == null || serviceType.equals("")) {
            return null;
        } else {
            return qTbServiceGrouop.serviceType.eq(serviceType);
        }
    }

    @Override
    public List<OprmngCodeRes> getMainOprmngCode(UserVo dto) {

        List<OprmngCodeRes> result = new ArrayList<>();

        if (dto.getRoleVal().equals(RoleResource.SYSTEMADMIN.getName())) {
            result = queryFactory.select(
                            Projections.fields(
                                    OprmngCodeRes.class,
                                    qTbServiceGrouop.serviceGroup,
                                    qTbServiceGrouop.serviceGroupName
                            )
                    ).from(qTbServiceGrouop)
                    .where(qTbServiceGrouop.serviceType.eq("M"))
                    .fetch();
            return result;
        } else {
            result = queryFactory.select(
                            Projections.fields(
                                    OprmngCodeRes.class,
                                    qTbServiceGrouop.serviceGroup,
                                    qTbServiceGrouop.serviceGroupName
                            )
                    ).from(qTbUserCust)
                    .innerJoin(qTbServiceGrouop).on(qTbUserCust.serviceGroup.eq(qTbServiceGrouop.serviceGroup))
                    .where(
                            qTbUserCust.userSeq.eq(dto.getUserSeq())
//                            , qTbServiceGrouop.serviceType.eq("M")
                    )
                    .groupBy(qTbServiceGrouop.serviceGroup,
                            qTbServiceGrouop.serviceGroupName)
                    .fetch();
            return result;
        }
    }

    @Override
    public List<SystemServiceGroupViewVo> getServiceGroupView(String serviceGroup) {

        List<SystemServiceGroupViewVo> result = new ArrayList<>();

        try {
            result = queryFactory.select(
                            Projections.fields(
                                    SystemServiceGroupViewVo.class,
                                    qTbServiceGrouop.custCode,
                                    qTbServiceGrouop.serviceGroup,
                                    qTbServiceGrouop.serviceGroupName,
                                    qTbServiceGrouop.serviceGroupDesc,
                                    qTbServiceGrouop.serviceType,
                                    qTbServiceGrouop.useYn,
                                    qTbIcsOprMngInfo.oprMngCode
                            )
                    ).from(qTbServiceGrouop)
                    .innerJoin(qTbIcsOprMngInfo).on(qTbServiceGrouop.serviceGroup.eq(qTbIcsOprMngInfo.serviceGroup))
                    .where(qTbServiceGrouop.serviceGroupUpper.eq(serviceGroup))
                    .groupBy(
                            qTbServiceGrouop.custCode,
                            qTbServiceGrouop.serviceGroup,
                            qTbServiceGrouop.serviceGroupName,
                            qTbServiceGrouop.serviceGroupDesc,
                            qTbServiceGrouop.serviceType,
                            qTbServiceGrouop.useYn,
                            qTbIcsOprMngInfo.oprMngCode)
                    .fetch();
        } catch (Exception e) {
            log.info("error - {}", e.getMessage());
        }
        return result;
    }

    @Override
    public List<OprmngCodeRes> getOprmngCodeAdmin(UserVo dto, String serviceType) {
        List<OprmngCodeRes> result = new ArrayList<>();
        return result = queryFactory.select(
                        Projections.fields(
                                OprmngCodeRes.class,
                                qTbIcsOprMngInfo.serviceGroup,
                                qTbServiceGrouop.serviceGroupName
                        )
                )
                .from(qTbServiceGrouop)
                .innerJoin(qTbIcsOprMngInfo).on(qTbServiceGrouop.serviceGroup.eq(qTbIcsOprMngInfo.serviceGroup))
                //현재 사용중인 서비스그룹의 하위검색
                .where(qTbServiceGrouop.serviceGroupUpper.eq(dto.getLastUseServiceGroup())
                        , serviceTypeEq(serviceType)
                )
                .fetch();
    }


}
