package com.tykj.dev.device.user.subject.service.impl;

import com.github.wenhao.jpa.PredicateBuilder;
import com.github.wenhao.jpa.Specifications;
import com.tykj.dev.config.cache.ConfigCache;
import com.tykj.dev.device.user.base.req.DropDownUserLocation;
import com.tykj.dev.device.user.base.req.NotIsUser;
import com.tykj.dev.device.user.base.req.UnitNameVo;
import com.tykj.dev.device.user.base.ret.*;
import com.tykj.dev.device.user.cache.UserCache;
import com.tykj.dev.device.user.read.service.MessageService;
import com.tykj.dev.device.user.read.subject.bto.MessageBto;
import com.tykj.dev.device.user.subject.dao.MgrcertDao;
import com.tykj.dev.device.user.subject.dao.UnitsDao;
import com.tykj.dev.device.user.subject.dao.UserDao;
import com.tykj.dev.device.user.subject.dao.UserRoleDao;
import com.tykj.dev.device.user.subject.entity.*;
import com.tykj.dev.device.user.subject.service.*;
import com.tykj.dev.misc.exception.ApiException;
import com.tykj.dev.misc.utils.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.persistence.Transient;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zjm
 * @version 1.0.0
 * @ClassName UserServiceImpl.java
 * @Description 用户逻辑层
 * @createTime 2020年07月27日 15:07:00
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Autowired
    UserDao userDao;
    @Autowired
    BCryptPasswordEncoder bCryptPasswordEncoder;
    @Autowired
    MgrcertDao mgrcertDao;
    @Autowired
    UnitsService unitsService;
    @Autowired
    UserRoleDao userRoleDao;
    @Autowired
    UserLogService userLogService;
    @Autowired
    AreaService areaService;

    @Autowired
    UserPublicService userPublicService;

    @Autowired
    UnitsDao unitsDao;

    @Autowired
    MessageService messageService;

    @Autowired
    UserCache userCache;

    @Autowired
    ConfigCache configCache;

    @Override
    public Map save(User user, SecurityUser securityUser) {
        Map<String, Object> map = new HashMap<>();
        String encode = bCryptPasswordEncoder.encode("qwer1234");
        user.setPassword(encode);
        user.setNoPassword("qwer1234");
        Units units = unitsService.findById(user.getUnitsId());
        user.setShowOrder(userDao.maxShowOrder(units.getUnitId())+1);
        //先判断用户名是否被注册
        User byName= userDao.findByNameAndUnitsId(user.getName(),user.getUnitsId());
        if (byName != null){
            map.put("error",byName);
            return map;
//            throw new ApiException(ResponseEntity.ok("同单位下有相同名称的专管员:"+user.getName()));
        }
        User byUsername = userDao.findByUsername(user.getUsername());
        if (byUsername != null){
            map.put("error",byUsername);
            return map;
        }
        User user1 = userDao.save(user);
        switch (units.getLevel()){
            case 1:
                userRoleDao.save(new UserRole(user1.getUserId(),1));
                break;
            case 2:
                userRoleDao.save(new UserRole(user1.getUserId(),2));
                break;
            case 3:
                userRoleDao.save(new UserRole(user1.getUserId(),3));
                break;
            default:
                log.info("[user] 添加转管员单位等级不存在：{}",units.getLevel());

        }
        messageService.add(new MessageBto(0,-1,securityUser.getCurrentUserInfo().getName()+"添加专管员"+user1.getName(),this.findAllLastUserids(securityUser.getCurrentUserInfo().getUserId())));
        userLogService.save(new UserLog(user1.getUserId(),new Date(),"专管员任命成功"));
        userCache.refresh(userDao.findAll());
        map.put("user1",user1);
        return map;
    }


    /**
     * 给密码加密bCryptPasswordEncoder
     * 在根据创建用户单位 给予不同的角色关联
     * @param user
     * @return
     */
    @Override
    public User save(User user) {
        String encode = bCryptPasswordEncoder.encode("qwer1234");
        user.setPassword(encode);
        Units units = unitsService.findById(user.getUnitsId());
        User user1 = userDao.save(user);
        switch (units.getLevel()){
            case 1:
                userRoleDao.save(new UserRole(user1.getUserId(),1));
            break;
            case 2:
                userRoleDao.save(new UserRole(user1.getUserId(),2));
            break;
            case 3:
                userRoleDao.save(new UserRole(user1.getUserId(),3));
                break;
            default:
               log.info("[user] 添加转管员单位等级不存在：{}",units.getLevel());

        }
        userLogService.save(new UserLog(user1.getUserId(),new Date(),"专管员任命成功"));
        userCache.refresh(userDao.findAll());
        return user1;
    }

    @Override
    public boolean delete(Integer id) {
        User user= findByUser(id);
        user.setDeleteTag(1);
        userDao.save(user);
        userCache.refresh(userDao.findAll());
        return true;
    }

    @Override
    public List<User> findAll() {
        return userDao.findAll();
    }

    @Override
    public User update(User user) {
        Optional<User> userOptional = userDao.findById(user.getUserId());
        if (userOptional.isPresent()){
            User user1= userOptional.get();
            user.setNoPassword(user1.getNoPassword());
            user.setShowOrder(user1.getShowOrder());
            user.setTrainStatus(user1.getTrainStatus());
            user.setIsDel(user1.getIsDel());
        }else {
         throw new ApiException(ResponseEntity.status(500).body("没找到对应的用户id"));
        }
        User user1 = userDao.save(user);
        userCache.refresh(userDao.findAll());
        return user1;
    }

    @Override
    public User findByUserName(String userName) {
        return userDao.findByUsername(userName);
    }


    @Override
    public List<UserShenRe> findByUserId(Integer userId) {

        return findByUniteId(userDao.findById(userId).get().getUnitsId());
    }

    @Override
    public List<UserShenRe> findByUniteId(Integer unitsId) {

        return userDao.findAllByUnitsId(unitsId).stream().filter(user -> user.getIsDel()==0 && user.getDeleteTag()==0).map(User::toRe).sorted(Comparator.comparing(UserShenRe::getShowOrder)).collect(Collectors.toList());
    }

    @Override
    public List<UserShenRe> findByUniteId1(Integer unitsId) {
        return userDao.findAllByUnitsId(unitsId).stream().filter(user -> user.getTrainStatus()!=5&&user.getIsDel()==0&& user.getDeleteTag()==0).map(User::toRe).sorted(Comparator.comparing(UserShenRe::getShowOrder)).collect(Collectors.toList());
    }

    @Override
    public List<User> findAllByUnite(Integer unitsId) {
        return userDao.findAllByUnitsId(unitsId).stream().filter(user -> user.getTrainStatus()!=5&&user.getIsDel()==0&& user.getDeleteTag()==0).collect(Collectors.toList());
    }


//    public UserPage findAllByUnitePage(UserConditionsVo userConditionsVo) {
//        Integer page = userConditionsVo.getPage();
//        Integer size = userConditionsVo.getSize();
//        List<MemberThat> memberThats = new ArrayList<>();
//        userDao.findAllByUnitsId(userConditionsVo.getUnitsId())
//                .stream()
//                .filter(user -> user.getTrainStatus()!=5)
//                .filter(user ->{
//                    boolean isNull=userConditionsVo.getDim()!=null;
//                    if (isNull) {
//                        boolean isName = user.getName().contains(userConditionsVo.getDim());
//                        boolean isSex = user.getSex() != 1 ? "男".contains(userConditionsVo.getDim()) : "女".contains(userConditionsVo.getDim());
//                        boolean isUnit = unitsService.findById(user.getUnitsId()).getName().contains(userConditionsVo.getDim());
//                        boolean isMobile=user.getMobile()!=null&&user.getMobile().contains(userConditionsVo.getDim());
//                        boolean isPosition = configCache.getPositionMap().get(user.getPosition()).contains(userConditionsVo.getDim());
//                        return  isName || isSex || isUnit || isPosition||isMobile;
//                    }else {
//                        return true;
//                    }
//                })
//             .forEach(
//                user -> {
//                    MemberThat memberThat = user.toVo();
//                    memberThat.setUnitsName(unitsService.findById(user.getUnitsId()).getName());
//                    Mgrcert mgrcert = mgrcertDao.findByUserId(user.getUserId());
//                    if (mgrcert != null) {
//                        memberThat.setCertName(mgrcert.getCertName());
//                        memberThat.setCertNum(mgrcert.getCertNum());
//                        memberThat.setIssueDate(mgrcert.getIssueDate());
//                        memberThat.setExpiryDate(mgrcert.getExpiryDate());
//                        memberThat.setIsExpiry(mgrcert.getIsExpiry());
//                        memberThat.setRemaining(mgrcert.getExpiryDate().getTime() - mgrcert.getIssueDate().getTime());
//                    } else {
//                        memberThat.setRemaining(0L);
//                    }
//                    memberThats.add(memberThat);
//                }
//        );
////        if (userConditionsVo.getDim()!=null){
////            memberThats= memberThats.stream().filter(memberThat -> memberThat.getName().contains(userConditionsVo.getDim())||memberThat.getSex()==1?"男".contains(userConditionsVo.getDim()):"女".equals(userConditionsVo.getDim())||
////                    memberThat.getUnitsName().contains(userConditionsVo.getDim())||memberThat.getPosition()==1?"领导".contains(userConditionsVo.getDim()):"专管员".contains(userConditionsVo.getDim())).collect(Collectors.toList());
////        }
//
//        memberThats.sort((o1, o2) -> {
//            //升序
//            return o2.getRemaining().compareTo(o1.getRemaining());
//        });
//
//
//        int count = memberThats.size();
//        if (size > count) {
//            return UserPage.builder()
//                    .total(count)
//                    .page(page)
//                    .size(size)
//                    .data(memberThats).build();
//        }
//        int countPage = count / size;
//        if (count % size != 0) {
//            countPage = countPage + 1;
//        }
//        if (page >= countPage) {
//            return UserPage.builder()
//                    .total(count)
//                    .page(page)
//                    .size(size)
//                    .data(memberThats.subList((page - 1) * size, count)).build();
//        } else {
//            return UserPage.builder()
//                    .total(count)
//                    .page(page)
//                    .size(size)
//                    .data(memberThats.subList((page - 1) * size, page * size)).build();
//        }
//
//    }
    @Override
    public UserPage findAllByUnitePage(UserConditionsVo userConditionsVo){
        Page<User> userPage= userDao.findAll(getUserSpecification(userConditionsVo),userConditionsVo.getPageable());
        List<MemberThat> list=new ArrayList<>();
        userPage.getContent().forEach(
                user -> {
                    MemberThat memberThat = user.toVo();
                    memberThat.setUnitsName(unitsService.findById(user.getUnitsId()).getName());
                    Mgrcert mgrcert = mgrcertDao.findByUserId(user.getUserId());
                    if (mgrcert != null) {
                        memberThat.setCertName(mgrcert.getCertName());
                        memberThat.setCertNum(mgrcert.getCertNum());
                        memberThat.setIssueDate(mgrcert.getIssueDate());
                        memberThat.setExpiryDate(mgrcert.getExpiryDate());
                        memberThat.setIsExpiry(mgrcert.getIsExpiry());
                        memberThat.setRemaining(mgrcert.getExpiryDate().getTime() - mgrcert.getIssueDate().getTime());
                    } else {
                        memberThat.setRemaining(0L);
                    }
                    list.add(memberThat);
                }
        );
        return UserPage.builder()
                .total((int)userPage.getTotalElements())
                .page(userPage.getPageable().getPageNumber())
                .size(userPage.getPageable().getPageSize())
                .data(list).build();
    }

    private Specification<User> getUserSpecification(UserConditionsVo userConditionsVo) {
        PredicateBuilder<User> predicateBuilder = Specifications.and();
        if (userConditionsVo.getType()==1){
            List<Integer> unitIds;
            if (userConditionsVo.getUnitsId()!=0) {
                List<Integer> ids = areaService.findIdQuerySubordinateIds(userConditionsVo.getUnitsId());
                 unitIds = unitsDao.findAllByAreaIdIn(ids).stream().map(Units::getUnitId).collect(Collectors.toList());
            }else {
                unitIds = unitsDao.findAllByType(2).stream().map(Units::getUnitId).collect(Collectors.toList());
            }
           predicateBuilder.in("unitsId",unitIds.toArray());
        }else if (userConditionsVo.getType()==2){
            predicateBuilder.eq("unitsId",userConditionsVo.getUnitsId());
        }
        predicateBuilder.eq("deleteTag",0);
        predicateBuilder.eq("isDel",0);
        predicateBuilder.notIn("trainStatus",5);
        if (userConditionsVo.getDim() != null) {
            Class<User> deviceLibraryEntity = User.class;
            Field[] declaredFields = deviceLibraryEntity.getDeclaredFields();
            PredicateBuilder<User> p = Specifications.or();
            for (Field field : declaredFields) {
                if (field.getType().equals(String.class) && field.getAnnotation(Transient.class) == null) {
                    p.like(field.getName(), "%" + userConditionsVo.getDim() + "%");
                }
            }
            predicateBuilder.predicate(p.build());
        }
        return predicateBuilder.build();

    }






    @Override
    public Integer updatePw(UserUpdatePw userUpdatePw) {
        Optional<User> userOpt = userDao.findById(userUpdatePw.getUserId());
        log.info("参数：{}",userUpdatePw);
        if (userOpt.isPresent()) {
            User user = userOpt.get();

            if (bCryptPasswordEncoder.matches(userUpdatePw.getPassword(),user.getPassword())) {
                user.setPassword(bCryptPasswordEncoder.encode(userUpdatePw.getNewPassWord()));
                user.setNoPassword(userUpdatePw.getNewPassWord());
                User user1 = userDao.save(user);
                userCache.refresh(userDao.findAll());
                return user1.getUserId();
            } else {
                return -1;
            }
        } else {
            return -2;
        }
    }

    @Override
    public MemberThat findById(Integer userId) {
        MemberThat memberThat = userDao.findById(userId).get().toVo();
        Mgrcert mgrcert = mgrcertDao.findByUserId(userId);
        memberThat.setUnitsName(unitsService.findById(memberThat.getUnitsId()).getName());
        if (mgrcert != null) {
            memberThat.setCertName(mgrcert.getCertName());
            memberThat.setCertNum(mgrcert.getCertNum());
            memberThat.setIssueDate(mgrcert.getIssueDate());
            memberThat.setExpiryDate(mgrcert.getExpiryDate());
            memberThat.setIsExpiry(mgrcert.getIsExpiry());
            memberThat.setRemaining(mgrcert.getExpiryDate().getTime() - mgrcert.getIssueDate().getTime());
        } else {
            memberThat.setRemaining(0L);
        }
        ConfigCache configCache = SpringUtils.getBean("initConfigCache");
        if (configCache!=null){
            memberThat.setPositionName(configCache.getPositionMap().get(memberThat.getPosition()));
        }
        return memberThat;
    }

    @Override
    public User findByUser(Integer userId) {
        Optional<User> optionalUser = userDao.findById(userId);
        if (optionalUser.isPresent()){
            return optionalUser.get();
        }else {
            throw new ApiException(ResponseEntity.status(500).body("[用户] 没有找到对应的id"+userId));
        }
    }

    @Override
    public List<User> findSubordinate(Integer userId) {
        Integer unitsId = userDao.findById(userId).get().getUnitsId();
        return userDao.findAllByUnitsIdIn(unitsService.findListSubordinateId(unitsId));

    }

//    @Override
//    public List<UserTrainVo> findByIdUserTarinVo(Integer userId) {
//        List<UserTrainVo> list = new ArrayList<>();
//        Integer unitsId = userDao.findById(userId).get().getUnitsId();
//        Units units = unitsService.findById(unitsId);
//        userDao.findAllByUnitsIdIn(unitsService.findListSubordinateId(unitsId)).forEach(
//                user -> {
//                    UserTrainVo userTrainVo = user.toUserTrainVo();
//                    if (user.getTrainStatus() == 1 || user.getTrainStatus() == 2) {
//                        userTrainVo.setIsMustJoin(0);
//                    } else {
//                        userTrainVo.setIsMustJoin(1);
//                    }
//                    userTrainVo.setUnitsName(unitsService.findById(user.getUnitsId()).getName());
//                    list.add(userTrainVo);
//                }
//        );
//        list.sort(Comparator.comparing(UserTrainVo::getIsMustJoin).reversed());
//        return list;
//    }

    @Override
    public List<UnitsTrainVo> findByIdUnitsTrainVo(Integer userId) {
        return unitsService.findListUnitsTrainVo(userDao.findById(userId).get().getUnitsId());
    }


//    @Override
//    public List<UserTrainVo> findByIdListUserTarinVo(List<Integer> userId) {
//        List<UserTrainVo> list = new ArrayList<>();
//        userDao.findAllByUserIdIn(userId).forEach(
//                user -> {
//                    UserTrainVo userTrainVo = user.toUserTrainVo();
//                    if (user.getTrainStatus() == 1 || user.getTrainStatus() == 2) {
//                        userTrainVo.setIsMustJoin(0);
//                    } else {
//                        userTrainVo.setIsMustJoin(1);
//                    }
//                    userTrainVo.setUnitsName(unitsService.findById(user.getUnitsId()).getName());
//                    list.add(userTrainVo);
//                }
//        );
//        return list;
//    }

    @Override
    public HandoverUser findByIdHandoverUser(Integer userId) {
        HandoverUser handoverUser = userDao.findById(userId).get().toHandoverUserVo();
        Mgrcert mgrcert = mgrcertDao.findByUserId(userId);
        if (handoverUser.getTrainStatus() != 2) {
            if (mgrcert != null) {
                handoverUser.setCertName(mgrcert.getCertName());
                handoverUser.setCertNum(mgrcert.getCertNum());
                handoverUser.setIssueDate(mgrcert.getIssueDate());
                handoverUser.setExpiryDate(mgrcert.getExpiryDate());
                handoverUser.setIsExpiry(mgrcert.getIsExpiry());
            }
            handoverUser.setUnitsName(unitsService.findById(handoverUser.getUnitsId()).getName());
        }
        return handoverUser;
    }

    @Override
    public List<UserSuperiorVo> findUserSuperiorVo(Integer userId) {

        List<UserSuperiorVo> list = new ArrayList<>();
        User user = userDao.findById(userId).get();

        userDao.findAllByUnitsIdIn(unitsService.findSuperiorByunitsId(user.getUnitsId())).stream().filter(user1 -> user1.getIsDel()==0&&user1.getTrainStatus()!=5&& user.getDeleteTag()==0).forEach(
                user1 -> {
                    UserSuperiorVo userSuperiorVo = user1.toUserSuperiorVo();
                    userSuperiorVo.setUnitsName(unitsService.findById(user1.getUnitsId()).getName());
                    list.add(userSuperiorVo);
                }
        );
        return list;
    }

    @Override
    public List<User> findUnitsIdInUsers(List<Integer> units) {
        return userDao.findAllByUnitsIdIn(units).stream().filter(user -> user.getTrainStatus()!=5 && user.getDeleteTag()==0 && user.getIsDel()==0).collect(Collectors.toList());
    }

    @Override
    public List<User> findAllUserIdInUser(List<Integer> userIds) {
        return userDao.findAllByUserIdIn(userIds);
    }

    @Override
    public List<Integer> findAllLastUserids(Integer userId) {
        User user=userDao.findById(userId).get();
        Units units= unitsDao.findById(user.getUnitsId()).get();
        Area area= areaService.findByid(units.getAreaId());

        return to(new ArrayList<>(),area);
    }

    @Override
    public void updateUserPass() {
        String encode = bCryptPasswordEncoder.encode("qwer1234");
       List<User> users=  userDao.findAll();
        users.forEach(
               user -> {
                   user.setPassword(encode);
                   user.setNoPassword("qwer1234");
               }
       );
        userDao.saveAll(users);
        userCache.refresh(userDao.findAll());
    }

    @Override
    public User addNoIsUser(NotIsUser notIsUser) {
        User user=new User();
        user.setName(notIsUser.getName());
        if (notIsUser.getUnitId()!=null) {
            user.setUnitsId(notIsUser.getUnitId());
        }else {
            throw new ApiException(ResponseEntity.status(500).body("[用户] 没有传单位id"));
        }
        user.setShowOrder(3);
        user.setTrainStatus(5);
        User user1 = userDao.save(user);
        userCache.refresh(userDao.findAll());
        return user1;
    }

    @Override
    public void replaceOptFor(DropDownUserLocation dropDownUserLocation) {
        List<User> users= userDao.findAllByUnitsId(dropDownUserLocation.getUnitId());
        users.forEach(
                user -> {
                    if (user.getUserId().equals(dropDownUserLocation.getUserId())){
                        user.setShowOrder(dropDownUserLocation.getLocationCode());
                    }else {
                        if (user.getShowOrder()>2|| user.getShowOrder().equals(dropDownUserLocation.getLocationCode())){
                            user.setShowOrder(3);
                        }
                    }
                }
        );
        userDao.saveAll(users);
    }

    @Override
    public List<UserShenRe> findUnitNameListUser(UnitNameVo unitNameVo) {

        return userDao.findAllByUnitsId(userPublicService.findUnitIdByName(unitNameVo.getUnitName())).stream().filter(user -> user.getIsDel()==0&& user.getDeleteTag()==0).map(User::toRe).collect(Collectors.toList());
    }

    @Override
    public List<UserShenRe> findUnitIdListUser(Integer unitId) {
        return userDao.findAllByUnitsId(unitId).stream().filter(user -> user.getTrainStatus()!=5).map(User::toRe).collect(Collectors.toList());
    }

    @Override
    public List<User> saveAll(List<User> users) {
        return userDao.saveAll(users);
    }

    @Override
    public void deleteById(Integer userId) {
           User user= findByUser(userId);
           user.setDeleteTag(1);
           userDao.save(user);
    }

    @Override
    public void updateUserTrainStatus(List<Integer> userIds, Integer status) {
     userDao.upDateUserIdsAndTrainStatus(userIds,status);
    }

    private List<Integer> to(List<Integer> ids,Area area){

        if (area.getFatherId()==null){
            return ids;
        }
        Area area1= areaService.findByid(area.getFatherId());
        List<Units> units= unitsDao.findAllByAreaId(area1.getId());
        ids.addAll(userDao.findAllByUnitsId(units.get(0).getUnitId()).stream().map(User::getUserId).collect(Collectors.toList()));
        return to(ids,area1);
    }


}
