package com.icomsys.main_vm.biz.common.system.service;


import com.google.gson.Gson;
import com.icomsys.main_vm.biz.advice.excep.CustomNotFoundException;
import com.icomsys.main_vm.biz.common.common.service.SequenceService;
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.login.service.LoginService;
import com.icomsys.main_vm.biz.common.system.vo.*;
import com.icomsys.main_vm.common.code.enumresource.RoleResource;
import com.icomsys.main_vm.db.jpa.entity.system.*;
import com.icomsys.main_vm.db.jpa.entity.system.id.TbUserAuthGroupId;
import com.icomsys.main_vm.db.jpa.entity.system.id.TbUserCustId;
import com.icomsys.main_vm.db.jpa.repo.system.*;
import com.querydsl.core.QueryResults;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class SystemUserAdminService {

    private final LoginService loginService;
    private final TbBotUserRepo tbBotUserRepo;
    private final TbServiceAuthGroupRepo tbServiceAuthGroupRepo;
    private final TbServiceGrouopRepo tbServiceGrouopRepo;
    private final PasswordEncoder passwordEncoder;
    private final SequenceService sequenceService;
    private final TbUserAuthGroupRepo tbUserAuthGroupRepo;
    private final TbUserCustRepo tbUserCustRepo;
    private final TbServiceGroupPolicyRepo tbServiceGroupPolicyRepo;
    private final TbIcsCustInfoRepo tbIcsCustInfoRepo;

    public DslDataTableRes<SystemBotUserRes> SystemUserAdminList(SystemBotUserReq dto) {
        DslDataTableRes result = new DslDataTableRes(tbBotUserRepo.SystemUserList(dto.ofUserVo(loginService.getUserVo()), RoleResource.USERADMIN.getName()));
        return result;
    }

    public List<SystemBotUserAuthGroupListRes> UserAdminAuthGroupList(String serviceGroup) {
        return tbServiceAuthGroupRepo.findByServiceGroup(serviceGroup).stream().map(e ->
                SystemBotUserAuthGroupListRes.builder().authGroupSeq(e.getAuthGroupSeq()).policyGroupName(e.getPolicyGroupName()).build()
        ).collect(Collectors.toList());
    }

    public String UserDoubleCheck(String userId) {
        String useYn = "N";
        if (tbBotUserRepo.existsByUserId(userId)) {
            return useYn;
        } else {
            return useYn = "Y";
        }
    }

    @Transactional
    public void userAdminSave(SystemBotUserSaveReq dto) throws CustomNotFoundException {
        TbServiceGrouop result = tbServiceGrouopRepo.findByServiceGroup(dto.getAddServiceAuthList().get(0).getAddService())
                .stream().findFirst().orElseThrow(() -> new CustomNotFoundException());

        String custCode = result.getCustCode();
        String upper = result.getServiceGroupUpper();

//        TbBotUser userSaveResult = tbBotUserRepo.save(dto.toUserCreateSave(loginService.getUserVo(), passwordEncoder,
//                custCode, sequenceService.UserSeqNext(), upper));


        TbBotUser userSaveResult = tbBotUserRepo.save(dto.toUserCreateSave(loginService.getUserVo(), passwordEncoder,
                custCode,  upper));

        //유저어드민 저장시에 유저 커스트와 유저오쓰그룹을 추가해줘야함.
        //유저어드민 자동생성해줘야할것 TB_USER_AUTH_GROUP, TB_SERVICE_AUTH_GROUP, TB_SERVICE_GROUP_POLICY, TB_USER_CUST

        List<TbUserAuthGroup> authList = new ArrayList<>();
        List<TbUserCust> userCusts = new ArrayList<>();
        for (addServiceAuthList e : dto.getAddServiceAuthList()) {
            userCusts.add(TbUserCust.builder()
                    .custCode(custCode)
                    .userSeq(userSaveResult.getUserSeq())
                    .serviceGroup(e.getAddService())
                    .build());
            for (Long f : e.getAuthList()) {
                authList.add(TbUserAuthGroup.builder()
                        .userSeq(userSaveResult.getUserSeq())
                        .authGroupSeq(f)
                        .serviceGroup(e.getAddService())
                        .custCode(custCode)
                        .build());
            }
        }
        log.info("authList saves - {}", new Gson().toJson(authList));
        tbUserAuthGroupRepo.saveAll(authList);
        tbUserCustRepo.saveAll(userCusts);


    }

    @Transactional
    public SystemBotUserViewRes UserAdminViewData(Long userSeq) throws CustomNotFoundException {


        TbBotUser tbu = tbBotUserRepo.findByUserSeqAndUseYn(userSeq, "Y").orElseThrow(() -> new CustomNotFoundException());

        SystemBotUserViewRes result = new SystemBotUserViewRes();
        List<SystemBotUserViewSubRes> resultSub = new ArrayList<>();
        List<SystemBotUserAuthGroupListRes> baseAuth = new ArrayList<>();
        List<SystemBotUserAuthGroupListRes> useAuth = new ArrayList<>();


        result.setUserSeq(tbu.getUserSeq());
        result.setUserId(tbu.getUserId());
        result.setUserName(tbu.getUserName());
        result.setEMail(tbu.getEMail());
        result.setMobileNo(tbu.getMobileNo());
        result.setUseYn(tbu.getUseYn());
        result.setLoginCheck(tbu.getLoginCheck());
        result.setLastUseServiceGroup(tbu.getLastUseServiceGroup());
        result.setRoleVal(tbu.getRoleVal());
        result.setUseAuthSeq(tbUserAuthGroupRepo.findByUserSeq(userSeq).stream().map(f -> f.getAuthGroupSeq()).collect(Collectors.toList()));
//        List<SystemBotUserViewSubRes> base = tbUserAuthGroupRepo.userUseAuthGroup(userSeq);
        List<String> base = tbUserAuthGroupRepo.findByUserSeq(userSeq).stream().map(e -> e.getServiceGroup())
                .distinct()
                .sorted()
                .collect(Collectors.toList());

        for (String e : base) {
            //그룹네임
            TbServiceGrouop sr = tbServiceGrouopRepo.findByServiceGroup(e).orElseThrow(() -> new CustomNotFoundException());
            List<SystemBotUserAuthGroupListRes> baseData = tbServiceAuthGroupRepo.findByServiceGroup(e)
                    .stream()
                    .map(f -> SystemBotUserAuthGroupListRes.builder()
                            .authGroupSeq(f.getAuthGroupSeq())
                            .policyGroupName(f.getPolicyGroupName())
                            .build())
                    .distinct()
                    .collect(Collectors.toList());
            List<Long> baseSeqData = new ArrayList<>();
            for (SystemBotUserAuthGroupListRes g : baseData) {
                baseSeqData.add(g.getAuthGroupSeq());
            }
            resultSub.add(SystemBotUserViewSubRes.builder()
                    .serviceGroup(sr.getServiceGroup())
                    .serviceName(sr.getServiceGroupName())
                    .baseAuthGroup(baseData)
                    .baseSeq(baseSeqData)
                    .build()
            );
        }

        result.setUseServiceGroup(resultSub);
        return result;

    }


    @Transactional
    public void userAdminUpdate(SystemBotUserUpdateReq dto) throws CustomNotFoundException {
        /*
        TbBotUser result = tbBotUserRepo.findById(dto.getUserSeq()).orElseThrow(() -> new CustomNotFoundException()).toUpdate(dto, loginService.getUserVo(), passwordEncoder);
        List<String> beforService = new ArrayList<>();
        List<String> baseService = new ArrayList<>();
        List<String> insertService = new ArrayList<>();
        List<TbUserAuthGroupId> delService = new ArrayList<>();
        List<TbUserCustId> delCust = new ArrayList<>();
        List<TbUserCust> insertCust = new ArrayList<>();
        List<Long> insertAuth = new ArrayList<>();
        List<TbUserAuthGroup> authSave = new ArrayList<>();
        Map<String, List<Long>> ServiceAuthSeqMap = new HashMap<>();
        //초기화
        beforService = tbUserAuthGroupRepo.findByUserSeq(dto.getUserSeq()).stream().map(e -> e.getServiceGroup())
                .distinct()
                .collect(Collectors.toList());
        //가지고있던 서비스그룹.
        for (addServiceAuthList e : dto.getAddServiceAuthList()) {
            //맵초기화
            ServiceAuthSeqMap.put(e.getAddService(), new ArrayList<>(e.getAuthList()));
            baseService.add(e.getAddService());
            insertService.add(e.getAddService());
        }
        log.info("ServiceAuthSeqMap map data - {}", new Gson().toJson(ServiceAuthSeqMap));
        log.info("baseService - {}", new Gson().toJson(baseService));
        log.info("beforService map data - {}", new Gson().toJson(beforService));
        //서비스그룹의 수량변화가 있는지 확인한다.
        for (String e : baseService) {
            //비교해서 인서트 리스트에 남는건 새로추가한목록.
            if (beforService.contains(e)) {
                insertService.remove(e);
                List<Long> authBase = new ArrayList<>();
                List<Long> authInsert = new ArrayList<>();
                authInsert = ServiceAuthSeqMap.get(e);
                authBase = ServiceAuthSeqMap.get(e);
                //해당 서비스의 그룹권한의 시퀀스가 변했는지 확인한다.
                List<Long> authBefor = tbUserAuthGroupRepo.findByUserSeqAndServiceGroupAndCustCode(result.getUserSeq(), e, result.getCustCode())
                        .stream().map(f -> f.getAuthGroupSeq())
                        .collect(Collectors.toList());
                log.info("authBefor 검사 기존값 = {}", new Gson().toJson(authBefor));
                for (Long g : authBase) {
                    if (authBefor.contains(e)) {
                        authInsert.remove(g);
                    } else {
                        log.info("다 델리트로 들어가니?" + e);
                        delService.add(TbUserAuthGroupId.builder()
                                .userSeq(dto.getUserSeq())
                                .authGroupSeq(g)
                                .serviceGroup(e)
                                .custCode(result.getCustCode())
                                .build());
                    }
                }
                authInsert.removeAll(authBefor);
                log.info("authInsert 지워진값확인  = {}", new Gson().toJson(authInsert));
                for (Long h : authInsert) {
                    log.info("추가 권한" + h);
                    authSave.add(TbUserAuthGroup.builder()
                            .userSeq(dto.getUserSeq())
                            .authGroupSeq(h)
                            .serviceGroup(e)
                            .custCode(result.getCustCode())
                            .build());
                }
            } else {
                //없는건 삭제리스트
                List<TbUserAuthGroup> delAuthSeq = tbUserAuthGroupRepo.findByUserSeqAndServiceGroupAndCustCode(result.getUserSeq(), e, result.getCustCode());
                log.info("delAuthSeq - {}", new Gson().toJson(delAuthSeq));
                for (TbUserAuthGroup f : delAuthSeq) {
                    log.info("삭제 권한" + f);
                    delService.add(TbUserAuthGroupId.builder()
                            .userSeq(dto.getUserSeq())
                            .authGroupSeq(f.getAuthGroupSeq())
                            .serviceGroup(e)
                            .custCode(result.getCustCode())
                            .build());
                }
                log.info("삭제 커스트" + e);
                delCust.add(TbUserCustId.builder()
                        .custCode(result.getCustCode())
                        .userSeq(dto.getUserSeq())
                        .serviceGroup(e)
                        .build());
            }
        }
        //인서트 서비스와 권한을 추가해준다.
        for (String e : insertService) {
            insertCust.add(TbUserCust.builder()
                    .custCode(result.getCustCode())
                    .serviceGroup(e)
                    .userSeq(dto.getUserSeq())
                    .build());
            log.info("추가 유저 커스트" + e);
            for (Long f : ServiceAuthSeqMap.get(e)) {
                log.info("추가 유저 권한그룹" + f);
                authSave.add(TbUserAuthGroup.builder()
                        .userSeq(dto.getUserSeq())
                        .authGroupSeq(f)
                        .serviceGroup(e)
                        .custCode(result.getCustCode())
                        .build());
            }
        }
        log.info("authSaveList - {}", new Gson().toJson(authSave));
        log.info("delServiceList - {}", new Gson().toJson(delService));
        tbUserCustRepo.saveAll(insertCust);
        tbUserCustRepo.deleteAllById(delCust);
        tbUserAuthGroupRepo.deleteAllById(delService);
        tbUserAuthGroupRepo.saveAll(authSave);
*/

        TbBotUser result = tbBotUserRepo.findById(dto.getUserSeq()).orElseThrow(() -> new CustomNotFoundException()).toUpdate(dto, loginService.getUserVo(), passwordEncoder);
        List<TbUserCustId> delCustList = tbUserCustRepo.findByUserSeq(dto.getUserSeq()).stream()
                .map(e -> TbUserCustId.builder()
                        .custCode(e.getCustCode())
                        .serviceGroup(e.getServiceGroup())
                        .userSeq(e.getUserSeq())
                        .build())
                .collect(Collectors.toList());

        List<TbUserAuthGroupId> delAuthGroupList = tbUserAuthGroupRepo.findByUserSeq(dto.getUserSeq()).stream()
                .map(e -> TbUserAuthGroupId.builder()
                        .userSeq(e.getUserSeq())
                        .authGroupSeq(e.getAuthGroupSeq())
                        .serviceGroup(e.getServiceGroup())
                        .custCode(e.getCustCode())
                        .build())
                .collect(Collectors.toList());

        List<TbUserCust> insertCustList = new ArrayList<>();
        List<TbUserAuthGroup> insertAuthGorupList = new ArrayList<>();
        for (addServiceAuthList e : dto.getAddServiceAuthList()) {
            insertCustList.add(TbUserCust.builder()
                    .custCode(result.getCustCode())
                    .serviceGroup(e.getAddService())
                    .userSeq(dto.getUserSeq())
                    .build());
            for (Long f : e.getAuthList()) {
                insertAuthGorupList.add(TbUserAuthGroup.builder()
                        .userSeq(dto.getUserSeq())
                        .authGroupSeq(f)
                        .serviceGroup(e.getAddService())
                        .custCode(result.getCustCode())
                        .build());
            }
        }

        tbUserCustRepo.deleteAllById(delCustList);
        tbUserAuthGroupRepo.deleteAllById(delAuthGroupList);
        tbUserCustRepo.saveAll(insertCustList);
        tbUserAuthGroupRepo.saveAll(insertAuthGorupList);
    }

    public List<SystemBotUserCustRes> UserAdminCustList() throws CustomNotFoundException {
        UserVo uv = loginService.getUserVo();
        List<SystemBotUserCustRes> result = new ArrayList<>();
        if (uv.getRoleVal().equals(RoleResource.SYSTEMADMIN.getName())) {
            return result = tbIcsCustInfoRepo.findAll().stream().map(e -> SystemBotUserCustRes.builder()
                            .custCode(e.getCustCode())
                            .custName(e.getCustName())
                            .build())
                    .collect(Collectors.toList());
        } else {
            TbIcsCustInfo adminresult = tbIcsCustInfoRepo.findById(uv.getCustCode()).orElseThrow(() -> new CustomNotFoundException());
            result.add(SystemBotUserCustRes.builder()
                    .custCode(adminresult.getCustCode())
                    .custName(adminresult.getCustName())
                    .build());
            return result;
        }
    }

    public List<OprmngCodeRes> UserAdminServiceList(String cust) {
        return tbServiceGrouopRepo.findByCustCodeAndServiceType(cust, "M").stream().map(e -> OprmngCodeRes.builder()
                .serviceGroup(e.getServiceGroup())
                .serviceGroupName(e.getServiceGroupName())
                .build()).collect(Collectors.toList());
    }


}
