package com.ningdatech.pmapi.user.manage;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.pmapi.common.helper.UserInfoHelper;
import com.ningdatech.pmapi.organization.model.entity.DingEmployeeInfo;
import com.ningdatech.pmapi.organization.service.IDingEmployeeInfoService;
import com.ningdatech.pmapi.organization.service.IDingOrganizationService;
import com.ningdatech.pmapi.sys.model.entity.Role;
import com.ningdatech.pmapi.sys.model.entity.UserRole;
import com.ningdatech.pmapi.sys.service.IRoleService;
import com.ningdatech.pmapi.sys.service.IUserRoleService;
import com.ningdatech.pmapi.user.constant.UserAvailableEnum;
import com.ningdatech.pmapi.user.entity.UserInfo;
import com.ningdatech.pmapi.user.model.po.*;
import com.ningdatech.pmapi.user.model.vo.ResUserDetailVO;
import com.ningdatech.pmapi.user.model.vo.ResUserInfoListVO;
import com.ningdatech.pmapi.user.model.vo.UserRoleVO;
import com.ningdatech.pmapi.user.security.auth.model.UserFullInfoDTO;
import com.ningdatech.pmapi.user.service.IUserInfoService;
import com.ningdatech.pmapi.user.util.LoginUserUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author liuxinxin
 * @date 2023/2/13 上午9:09
 */
@Component
@RequiredArgsConstructor
public class UserInfoManage {

    private final IDingOrganizationService iDingOrganizationService;
    private final IDingEmployeeInfoService iDingEmployeeInfoService;
    private final IUserInfoService iUserInfoService;
    private final IUserRoleService iUserRoleService;
    private final IRoleService iRoleService;
    private final UserInfoHelper userInfoHelper;

    public PageVo<ResUserInfoListVO> list(ReqUserInfoListPO reqUserInfoListPO) {
        LambdaQueryWrapper<DingEmployeeInfo> wrapper = Wrappers.lambdaQuery(DingEmployeeInfo.class)
                .eq(DingEmployeeInfo::getMainJob, "true")
                .eq(StringUtils.isNotBlank(reqUserInfoListPO.getOrgCode()), DingEmployeeInfo::getOrganizationCode, reqUserInfoListPO.getOrgCode());

        Page<DingEmployeeInfo> page = iDingEmployeeInfoService.page(new Page<>(reqUserInfoListPO.getPageNumber(), reqUserInfoListPO.getPageSize()), wrapper);
        List<DingEmployeeInfo> records = page.getRecords();
        long total = page.getTotal();
        List<ResUserInfoListVO> resUserInfoListVOList = new ArrayList<>();
        if (records != null && records.size() > 0) {
            List<String> employeeCodeList = records.stream().map(DingEmployeeInfo::getEmployeeCode)
                    .distinct().collect(Collectors.toList());

            Map<String, UserInfo> employeeCodeAvailableMap = new HashMap<>();
            if (CollUtil.isNotEmpty(employeeCodeList)) {
                employeeCodeAvailableMap = iUserInfoService.list(Wrappers.lambdaQuery(UserInfo.class)
                        .in(UserInfo::getEmployeeCode, employeeCodeList))
                        .stream().collect(Collectors.toMap(UserInfo::getEmployeeCode, Function.identity()));
            }


            Map<String, UserInfo> finalEmployeeCodeAvailableMap = employeeCodeAvailableMap;
            resUserInfoListVOList = records.stream()
                    .map(r -> {
                        ResUserInfoListVO resListVO = new ResUserInfoListVO();
                        resListVO.setName(r.getEmployeeName());
                        resListVO.setOrgName(r.getOrganizationCode());
                        resListVO.setOrgCode(r.getOrganizationCode());
                        // TODO 从用户信息中获取
                        // 从所属组织中获取
//                        resListVO.setRegionId();

                        UserInfo userInfo = finalEmployeeCodeAvailableMap.get(r.getEmployeeCode());
                        if (Objects.nonNull(userInfo)) {
                            resListVO.setPhoneNo(userInfo.getMobile());
                            if (StringUtils.isNotBlank(userInfo.getAvailable())
                                    && UserAvailableEnum.ENABLE.name().equals(userInfo.getAvailable())) {
                                resListVO.setStatus(UserAvailableEnum.ENABLE.name());
                            } else {
                                resListVO.setStatus(UserAvailableEnum.DISABLE.name());
                            }
                            resListVO.setUserId(userInfo.getId());
                        } else {
                            resListVO.setStatus(UserAvailableEnum.DISABLE.name());
                        }
                        resListVO.setUpdateTime(r.getUpdateOn());
//                        从用户信息中获取
                        resListVO.setEmployeeCode(r.getEmployeeCode());
                        resListVO.setUserRoleList(getUserRoleVOList(resListVO.getUserId()));
                        return resListVO;
                    }).collect(Collectors.toList());
        }

        PageVo<ResUserInfoListVO> pageVo = new PageVo<>();
        pageVo.setTotal(total);
        pageVo.setRecords(resUserInfoListVOList);
        return pageVo;
    }


    private List<UserRoleVO> getUserRoleVOList(Long userId) {
        List<UserRoleVO> userRoleInfoList = new ArrayList<>();
        if (Objects.isNull(userId)) {
            return userRoleInfoList;
        }
        List<UserRole> userRoleList = iUserRoleService.list(Wrappers.lambdaQuery(UserRole.class)
                .eq(UserRole::getUserId, userId));
        if (CollUtil.isNotEmpty(userRoleList)) {
            List<Long> roleIdList = userRoleList.stream().map(UserRole::getRoleId).collect(Collectors.toList());
            List<Role> roleList = iRoleService.list(Wrappers.lambdaQuery(Role.class).in(Role::getId, roleIdList));
            userRoleInfoList = roleList.stream().map(r -> {
                UserRoleVO userRoleVO = new UserRoleVO();
                userRoleVO.setId(r.getId());
                userRoleVO.setName(r.getName());
                return userRoleVO;
            }).collect(Collectors.toList());
        }
        return userRoleInfoList;
    }

    public void disableOrEnable(ReqUserDisableOrEnablePO reqUserDisableOrEnablePO) {
        Long userId = generateUserId(reqUserDisableOrEnablePO.getEmployeeCode());
        UserInfo userInfo = iUserInfoService.getById(userId);
        userInfo.setAvailable(reqUserDisableOrEnablePO.getOperation());
        iUserInfoService.updateById(userInfo);
    }

    public ResUserDetailVO userInfoDetail(ReqUserDetailPO reqUserDetailPO) {
        Long userId = generateUserId(reqUserDetailPO.getEmployeeCode());
        UserInfo userInfo = iUserInfoService.getById(userId);
        if (Objects.isNull(userInfo)) {
            return null;
        }
        ResUserDetailVO resUserDetailVO = new ResUserDetailVO();
        resUserDetailVO.setRealName(userInfo.getRealName());
        resUserDetailVO.setUserId(userInfo.getId());
        resUserDetailVO.setPhoneNo(userInfo.getMobile());
        resUserDetailVO.setStatus(userInfo.getAvailable());

        // 装配用户角色信息列表
        List<UserRole> userRoleList = iUserRoleService.list(Wrappers.lambdaQuery(UserRole.class)
                .eq(UserRole::getUserId, userId));
        List<UserRoleVO> userRoleInfoList = new ArrayList<>();
        if (CollUtil.isNotEmpty(userRoleList)) {
            List<Long> roleIdList = userRoleList.stream().map(UserRole::getRoleId).collect(Collectors.toList());
            List<Role> roleList = iRoleService.list(Wrappers.lambdaQuery(Role.class).in(Role::getId, roleIdList));
            userRoleInfoList = roleList.stream().map(r -> {
                UserRoleVO userRoleVO = new UserRoleVO();
                userRoleVO.setId(r.getId());
                userRoleVO.setName(r.getName());
                return userRoleVO;
            }).collect(Collectors.toList());
        }
        resUserDetailVO.setUserRoleInfoList(userRoleInfoList);
        return resUserDetailVO;
    }

    @Transactional(rollbackFor = Exception.class)
    public void userInfoDetailEdit(ReqUserDetailEditPO reqUserDetailEditPO) {
        Long userId = generateUserId(reqUserDetailEditPO.getEmployeeCode());

        UserInfo userInfo = iUserInfoService.getById(userId);
        if (Objects.isNull(userInfo)) {
            return;
        }
        userInfo.setMobile(reqUserDetailEditPO.getPhoneNo());
        userInfo.setAvailable(reqUserDetailEditPO.getStatus());
        iUserInfoService.updateById(userInfo);

        List<UserRoleVO> userRoleInfoList = reqUserDetailEditPO.getUserRoleInfoList();
        iUserRoleService.remove(Wrappers.lambdaQuery(UserRole.class).eq(UserRole::getUserId, userId));
        if (CollUtil.isNotEmpty(userRoleInfoList)) {
            List<UserRole> userRoleList = userRoleInfoList.stream().map(r -> {
                UserRole saveRecord = new UserRole();
                saveRecord.setRoleId(r.getId());
                saveRecord.setUserId(userId);
                return saveRecord;
            }).collect(Collectors.toList());
            iUserRoleService.saveBatch(userRoleList);
        }

    }

    @Transactional(rollbackFor = Exception.class)
    public Long generateUserId(String employeeCode) {
        UserInfo userInfo = iUserInfoService.getOne(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getEmployeeCode, employeeCode));
        if (Objects.isNull(userInfo)) {
            List<DingEmployeeInfo> dingEmployeeInfoList = iDingEmployeeInfoService
                    .list(Wrappers.lambdaQuery(DingEmployeeInfo.class)
                            .eq(DingEmployeeInfo::getEmployeeCode, employeeCode)
                            .eq(DingEmployeeInfo::getMainJob, "true"));
            if (CollUtil.isEmpty(dingEmployeeInfoList)) {
                throw new BizException("员工账号不存在");
            }
            DingEmployeeInfo dingEmployeeInfo = dingEmployeeInfoList.get(0);
            userInfo = UserInfo.builder()
                    .accountId(dingEmployeeInfo.getAccountId())
                    .username(dingEmployeeInfo.getEmployeeName())
                    .realName(dingEmployeeInfo.getEmployeeName())
                    .employeeCode(dingEmployeeInfo.getEmployeeCode())
                    .available(UserAvailableEnum.DISABLE.name())
                    .createBy(-1L)
                    .updateBy(-1L)
                    .createOn(LocalDateTime.now())
                    .updateOn(LocalDateTime.now())
                    .build();
            iUserInfoService.save(userInfo);
        }
        return userInfo.getId();
    }


    public ResUserDetailVO currentUserInfo() {
        Long userId = LoginUserUtil.getUserId();
        UserInfo userInfo = iUserInfoService.getById(userId);
        if (Objects.isNull(userInfo)) {
            return null;
        }
        ResUserDetailVO resUserDetailVO = new ResUserDetailVO();
        resUserDetailVO.setRealName(userInfo.getRealName());
        resUserDetailVO.setUserId(userInfo.getId());
        resUserDetailVO.setPhoneNo(userInfo.getMobile());
        resUserDetailVO.setStatus(userInfo.getAvailable());

        // 装配用户角色信息列表
        List<UserRole> userRoleList = iUserRoleService.list(Wrappers.lambdaQuery(UserRole.class)
                .eq(UserRole::getUserId, userId));
        List<UserRoleVO> userRoleInfoList = new ArrayList<>();
        if (CollUtil.isNotEmpty(userRoleList)) {
            List<Long> roleIdList = userRoleList.stream().map(UserRole::getRoleId).collect(Collectors.toList());
            List<Role> roleList = iRoleService.list(Wrappers.lambdaQuery(Role.class).in(Role::getId, roleIdList));
            userRoleInfoList = roleList.stream().map(r -> {
                UserRoleVO userRoleVO = new UserRoleVO();
                userRoleVO.setId(r.getId());
                userRoleVO.setName(r.getName());
                return userRoleVO;
            }).collect(Collectors.toList());
        }
        resUserDetailVO.setUserRoleInfoList(userRoleInfoList);
        UserFullInfoDTO userFullInfo = userInfoHelper.getUserFullInfo(userId);
        if(Objects.nonNull(userFullInfo)){
            resUserDetailVO.setOrgCode(userFullInfo.getOrganizationCode());
            resUserDetailVO.setOrgName(userFullInfo.getOrganizationName());
            resUserDetailVO.setRegionCode(userFullInfo.getRegionCode());
        }
        return resUserDetailVO;
    }

    public void generationLogin(ReqGenerationLoginPO reqGenerationLoginPO) {
        Long userId = reqGenerationLoginPO.getUserId();
        UserInfo userInfo = iUserInfoService.getById(userId);
        if (Objects.isNull(userInfo)) {
            throw new BizException("该员工账号处于禁用状态中，无法使用");
        }
        if (!UserAvailableEnum.ENABLE.name().equals(userInfo.getAvailable())) {
            throw new BizException("该员工账号处于禁用状态中，无法使用");
        }
        UserFullInfoDTO userFullInfo = userInfoHelper.getUserFullInfo(userId);


//        ReqGenerationLoginPO reqGenerationLoginPO
    }

//    public void autoLogin(Long userId){
//        userDetailsService.loadUserByUsername(userId + UserDeatilsServiceConstant.USER_DETAILS_SERVICE_SEPARATOR + LoginTypeEnum.USERNAME_PASSWORD_LOGIN.name());
//
//        CredentialAuthToken token = new CredentialAuthToken(email, password);
//        try {
//            token.setDetails(new WebAuthenticationDetails(httpServletRequest));
//            UsernamePasswordAuthToken authenticatedUser = (UsernamePasswordAuthToken)usernamePasswordAuthSecurityConfig
//                    .getAuthenticationManager().authenticate(token);
//            SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
//            httpServletRequest.getSession().setAttribute(
//                    HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
//            String sessionId = httpServletRequest.getSession().getId();
//            putSessionIdToCache(LoginUserUtil.getUserId(), sessionId);
//        } catch (
//                AuthenticationException e) {
//            throw new RuntimeException("autoLogIn Authentication failed!", e);
//        }
//    }


}
