package jnpf.attendance.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import jnpf.attendance.mapper.*;
import jnpf.attendance.service.*;
import jnpf.base.ActionResult;
import jnpf.base.vo.PageListVO;
import jnpf.base.vo.PaginationVO;
import jnpf.dto.PageDto;
import jnpf.entity.AttendanceGroupUser;
import jnpf.entity.attendance.AttendanceMachineManage;
import jnpf.entity.attendance.AttendanceMachineSync;
import jnpf.entity.attendance.AttendanceRuleScope;
import jnpf.entity.attendance.AttendanceUserFace;
import jnpf.enums.attendance.ActionEnum;
import jnpf.enums.attendance.MachineEnum;
import jnpf.enums.attendance.ScopeBizType;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.*;
import jnpf.model.attendance.vo.AttendanceGroupVo;
import jnpf.model.attendance.vo.AttendanceMachineManageVo;
import jnpf.model.attendance.vo.MachineScopeVo;
import jnpf.model.attendance.vo.attendance.GroupMiniVo;
import jnpf.model.attendance.vo.attendance.GroupUserMiniVo;
import jnpf.model.attendance.vo.attendance.LogMiniVo;
import jnpf.permission.V2UserApi;
import jnpf.permission.eum.v2.OrganizeCategoryEnums;
import jnpf.permission.eum.v2.UserWorkStatusEnums;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.permission.vo.v2.user.UserBoundVO;
import jnpf.util.*;
import jnpf.util.attendance.RuleScopeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 考勤机管理服务实现
 *
 * @author yanwenfu
 * @create 2024-09-10
 */
@Slf4j
@Service
public class AttendanceMachineManageServiceImpl implements AttendanceMachineManageService {

    @Resource
    private AttendanceMachineManageMapper attendanceMachineManageMapper;
    @Resource
    private AttendanceMachineLogMapper attendanceMachineLogMapper;
    @Resource
    private AttendanceGroupMapper attendanceGroupMapper;
    @Resource
    private AttendanceGroupService attendanceGroupService;
    @Resource
    private AttendanceGroupUserMapper attendanceGroupUserMapper;
    @Resource
    private AttendanceUserFaceMapper attendanceUserFaceMapper;
    @Resource
    private AttenceMachineService attenceMachineService;
    @Resource
    private AttendanceMachineSyncService attendanceMachineSyncService;
    @Resource
    private RuleScopeUtil ruleScopeUtil;
    @Autowired
    private V2UserApi v2UserApi;
    @Autowired
    private RedisUtil redisUtil;

    public static final String formatOrg = "【%s个组织】";
    public static final String formatUser = "【%s位成员】";
    @Autowired
    private AttendanceUserService attendanceUserService;

    @Override
    public List<GroupMiniVo> getGroupList(String machineId) {

        List<AttendanceGroupVo> authGroupList = attendanceGroupService.queryGroupListNew(null, new GroupQueryDto());
        if (null == authGroupList || authGroupList.isEmpty()) {
            return List.of();
        }
        List<String> authGroupIds = authGroupList.stream().filter(v -> v.getIsGray().equals(Boolean.FALSE)).map(AttendanceGroupVo::getId).collect(Collectors.toList());
        List<GroupMiniVo> list;
        if (StringUtils.isEmpty(machineId)) {
            // 考勤机id为空 查询所有考勤组
            list = attendanceGroupMapper.getAllGroupByLevel(null);
        } else {
            // 不为空 查询考勤机绑定的考勤组
            String groupIds = attendanceMachineManageMapper.getGroupIdsByMachine(machineId);
            if (StringUtils.isEmpty(groupIds)) {
                return new ArrayList<>();
            }
            String[] split = groupIds.split(",");
            list = attendanceGroupMapper.getAllGroupByLevel(Arrays.asList(split));
        }
        list = list.stream().filter(v -> authGroupIds.contains(v.getGroupId())).collect(Collectors.toList());
        return list;
    }

    @Override
    public PageListVO<AttendanceMachineManageVo> getMachineList(MachineQueryDto queryDto) {

        if (queryDto.getCurrentPage() == 0) {
            queryDto.setCurrentPage(1);
        }
        Integer scopeType = null;
        List<String> scopeValueList = new ArrayList<>();
        if (StringUtils.isNotEmpty(queryDto.getOrganizeId())) {
            // 判定是组织还是班组, 组织过滤适配范围的组织, 班组过滤组织范围的人
            if (queryDto.getOrganizeCategory().equals(OrganizeCategoryEnums.TEAM)) {
                scopeType = ConstantUtil.RULE_SCOPE_USER;
                List<UserBoundVO> userList = getOrgUserList(List.of(queryDto.getOrganizeId()));
                List<String> collect = userList.stream().map(UserBoundVO::getId).collect(Collectors.toList());
                scopeValueList.addAll(collect);
            } else {
                scopeType = ConstantUtil.RULE_SCOPE_ORG;
                scopeValueList.add(queryDto.getOrganizeId());
            }
        }
        // 无数据时使用
        PageListVO<AttendanceMachineManageVo> returnPage = new PageListVO<>();
        returnPage.setList(new ArrayList<>());
        PaginationVO pagination = new PaginationVO();
        pagination.setTotal(0);
        pagination.setPageSize((long) queryDto.getPageSize());
        pagination.setCurrentPage(0L);
        returnPage.setPagination(pagination);
        // 查询
        List<AttendanceMachineManage> dbList = attendanceMachineManageMapper.getMachineList(queryDto.getMachineKind(), queryDto.getKeywords(),
                scopeType, scopeValueList, ScopeBizType.ATTENDANCE_MACHINE.getValue());
        if (dbList.isEmpty()) {
            return returnPage;
        }
        List<AttendanceMachineManageVo> list = JsonUtil.getJsonToList(dbList, AttendanceMachineManageVo.class);
        list.forEach(v -> {
            String strOrg = v.getOrgCount() > 0 ? String.format(formatOrg, v.getOrgCount()) : "";
            String strUser = v.getUserCount() > 0 ? String.format(formatUser, v.getUserCount()) : "";
            String result = Stream.of(strOrg, strUser)
                    .filter(s -> !s.isEmpty())
                    .collect(Collectors.joining("、"));
            v.setScope(result);
            setOnline(v);
        });
        int total = attendanceMachineManageMapper.getTotal();
        pagination.setTotal(total);
        pagination.setCurrentPage((long) queryDto.getCurrentPage());
        pagination.setPageSize((long) queryDto.getPageSize());
        long startPage = (pagination.getCurrentPage() - 1) * pagination.getPageSize();
        // 数据筛选
        if (null != queryDto.getOnline()) {
            list = list.stream().filter(v -> v.getOnline().equals(queryDto.getOnline())).skip(startPage).limit(pagination.getPageSize()).collect(Collectors.toList());
        } else {
            list = list.stream().skip(startPage).limit(pagination.getPageSize()).collect(Collectors.toList());
        }
        returnPage.setList(list);
        returnPage.setPagination(pagination);
        return returnPage;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeMachineRelation(List<String> addUserIds, String moveTo, List<String> delGroupIds) {

        int size = 0;
        for (String groupId : delGroupIds) {
            // 查询所有关联此考勤组的考勤机
            List<AttendanceMachineManage> machineList = attendanceMachineManageMapper.getRelationMachineByGroupId(groupId);
            if (machineList.isEmpty()) {
                return;
            }
            // 考勤机移除关联
            machineList.forEach(machine -> {
                String[] split = machine.getGroupIds().split(",");
                StringBuilder sb = new StringBuilder();
                for (String str : split) {
                    if (str.equals(groupId)) {
                        continue;
                    }
                    sb.append(str).append(",");
                }
                attendanceMachineManageMapper.updateRelationGroup(machine.getId(), sb.length() > 0 ? sb.substring(0, sb.length() - 1) : "");
            });
            // 查询考勤组用户
            List<String> userIds = attendanceGroupUserMapper.getGroupUserListByIds(List.of(groupId));
            if (!userIds.isEmpty()) {
                // 相关考勤机移除这些用户
                machineList.forEach(machine -> attenceMachineService.deleteUserList(machine.getType(), machine.getMac(), userIds));
            }
            size += machineList.size();
        }
        // 需要移动到别的考勤组的成员
        if (StringUtils.isNotEmpty(moveTo) && !addUserIds.isEmpty()) {
            // 查询与考勤组相关的考勤机, 将成员下发到考勤机
            List<AttendanceMachineManage> machineList = attendanceMachineManageMapper.getRelationMachineByGroupId(moveTo);
            if (!machineList.isEmpty()) {
                // 查询用户信息
//                Map<String, PartUserInfoVo> userMap = userApi.getInfoMapByIds(addUserIds);
                ActionResult<List<UserBoundVO>> userList = v2UserApi.getAllUserInfoBatch(addUserIds, null);
                Map<String, UserBoundVO> userMap = new HashMap<>();
                if (200 == userList.getCode() && CollectionUtil.isNotEmpty(userList.getData())) {
                    userMap = userList.getData().stream().collect(Collectors.toMap(UserBoundVO::getId, Function.identity())) ;
                }
                // 下发成员到考勤机
                Map<String, UserBoundVO> finalUserMap = userMap;
                addUserIds.forEach(userId -> {
                    UserBoundVO userBoundVO = finalUserMap.get(userId);
                    PartUserInfoVo user = BeanUtil.copyProperties(userBoundVO, PartUserInfoVo.class);
//                    PartUserInfoVo user = userMap.get(userId);
                    if (null != user) {
                        user.setRealName(userBoundVO.getUserName());
                        machineList.forEach(machine -> attenceMachineService.sendUserToMachine(machine.getType(), user, machine.getMac()));
                    }
                });
            }
        }
    }

    private void setOnline(AttendanceMachineManageVo v) {

        MachineEnum machineEnum = MachineEnum.getMachineEnum(v.getType());
        if (null == machineEnum) {
            v.setOnline(ConstantUtil.NUM_FALSE);
        } else {
            switch (machineEnum) {
                case KAI_JIA_YI:
                    String mac = redisUtil.getHashValues(String.format(ConstantUtil.ONLINE_MAC, machineEnum.getValue()), v.getMac());
                    v.setOnline(StringUtils.isEmpty(mac) ? ConstantUtil.NUM_FALSE : ConstantUtil.NUM_TRUE);
                    break;
                case MAO_TONG:
                    String key = String.format(ConstantUtil.ONLINE_MAC, machineEnum.getValue());
                    String values = redisUtil.getHashValues(key, UserProvider.getUser().getTenantId());
                    if (StringUtils.isEmpty(values)) {
                        v.setOnline(ConstantUtil.NUM_FALSE);
                    } else {
                        v.setOnline(values.contains(v.getMac()) ? ConstantUtil.NUM_TRUE : ConstantUtil.NUM_FALSE);
                    }
                    break;
                case KE_MI:
                    Object str = redisUtil.getString(ConstantUtil.KE_MI + v.getMac());
                    v.setOnline(null == str ? ConstantUtil.NUM_FALSE : ConstantUtil.NUM_TRUE);
                    break;
                default:
                    v.setOnline(ConstantUtil.NUM_FALSE);
                    break;
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addMachine(MachineDto machineDto) throws HandleException {

        // 判断考勤机名称不能重复
        int nameCount = attendanceMachineManageMapper.getMachineNameCount(machineDto.getName(), null);
        if (nameCount > 0) {
            throw new HandleException("该考勤机已存在，请换个名称！");
        }
        // 判断考勤机Mac地址不能重复
        int macCount = attendanceMachineManageMapper.getMachineMacCount(machineDto.getName(), null);
        if (macCount > 0) {
            throw new HandleException("该考勤机ID已存在，请检查考勤机ID是否输入错误");
        }
        AttendanceMachineManage machineManage = JsonUtil.getJsonToBean(machineDto, AttendanceMachineManage.class);
        machineManage.setId(FtbUtil.getId());
        attendanceMachineManageMapper.insert(machineManage);
        // 添加考勤机租户关系到redis
        redisUtil.insertHash(ConstantUtil.DEVICE_TENANT, machineDto.getMac(), UserProvider.getUser().getTenantId());
        // 新增适配范围
        List<AttendanceRuleScope> ruleScopeList = ruleScopeUtil.getRuleScopeList(machineManage.getId(), ConstantUtil.SCOPE_ORG_USER,
                MutablePair.of(machineDto.getOrganizeList(), machineDto.getUserIdList()), ScopeBizType.ATTENDANCE_MACHINE);
        ruleScopeUtil.saveBatch(ruleScopeList);
        // 查询用户信息并下发到考勤机
        getInfoAndSendToMachine(machineDto.getType(), machineDto.getMac(), machineDto.getOrganizeList(), machineDto.getUserIdList());
    }

    private void getInfoAndSendToMachine(String type, String mac, List<String> organizeList, List<String> userIdList) {
        // 组织成员查询
        List<UserBoundVO> userList = getOrgUserList(organizeList);
        // 成员列表信息
        if (null != userIdList && !userIdList.isEmpty()) {
            ActionResult<List<UserBoundVO>> userResult = v2UserApi.getAllUserInfoBatch(userIdList, UserProvider.getUser().getTenantId());
            if (null != userResult && 200 == userResult.getCode()) {
                userList.addAll(userResult.getData());
            }
        }
        // 下发成员到考勤机
        Set<String> userSet = new HashSet<>();
        userList.forEach(userBoundVO -> {
            if (userSet.add(userBoundVO.getId())) {
                PartUserInfoVo user = new PartUserInfoVo();
                user.setUserId(userBoundVO.getId());
                user.setRealName(userBoundVO.getUserName());
                user.setUserNo(userBoundVO.getUserNo());
                user.setHeadIcon(userBoundVO.getHeadIcon());
                user.setUserId(userBoundVO.getId());
                user.setRealName(userBoundVO.getUserName());
                user.setGender(userBoundVO.getGender());
                attenceMachineService.sendUserToMachine(type, user, mac);
            }
        });
    }

    private List<UserBoundVO> getOrgUserList(List<String> organizeList) {

        List<UserBoundVO> userList = new ArrayList<>();
        if (null != organizeList && !organizeList.isEmpty()) {
            ActionResult<List<UserBoundVO>> orgResult = v2UserApi.listTargetOrganizesOrHaveChild(organizeList,
                    Boolean.FALSE, List.of(UserWorkStatusEnums.RESIGNED), UserProvider.getUser().getTenantId());
            if (null != orgResult && 200 == orgResult.getCode()) {
                userList.addAll(orgResult.getData());
            }
        }
        return userList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateMachine(String id, MachineUpdateDto machineUpdateDto) throws HandleException {

        AttendanceMachineManage machineManage = attendanceMachineManageMapper.selectById(id);
        if (null == machineManage) {
            throw new HandleException("未找到该考勤机");
        }
        // 判断考勤机名称不能重复
        int nameCount = attendanceMachineManageMapper.getMachineNameCount(machineUpdateDto.getName(), id);
        if (nameCount > 0) {
            throw new HandleException("该考勤机已存在，请换个名称！");
        }
        // 适配范围变更
        UpdateChangeDto updateChange = ruleScopeUtil.updateRuleScopeList(machineManage.getId(), ConstantUtil.SCOPE_ORG_USER, ConstantUtil.SCOPE_ORG_USER,
                MutablePair.of(machineUpdateDto.getOrganizeList(), machineUpdateDto.getUserIdList()), ScopeBizType.ATTENDANCE_MACHINE);
        // 需要删除的
        List<UserBoundVO> delUserList = getOrgUserList(updateChange.getDelOrgList());
        List<String> delUserIds = delUserList.stream().map(UserBoundVO::getId).collect(Collectors.toList());
        delUserIds.addAll(updateChange.getDelUserList());
        if (!delUserIds.isEmpty()) {
            // 从考勤机中移除
            attenceMachineService.deleteUserList(machineManage.getType(), machineManage.getMac(), delUserIds);
        }
        // 需要新增的
        // 查询用户信息并下发到考勤机
        getInfoAndSendToMachine(machineManage.getType(), machineManage.getMac(), updateChange.getAddOrgList(), updateChange.getAddUserList());
        // 更新考勤机信息
        machineManage.setName(machineUpdateDto.getName());
        machineManage.setLastModifyTime(new Date());
        machineManage.setLastModifyUserId(UserProvider.getUser().getUserId());
        attendanceMachineManageMapper.updateById(machineManage);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteMachine(String id) throws HandleException {

        AttendanceMachineManage machineManage = attendanceMachineManageMapper.selectById(id);
        if (null == machineManage) {
            throw new HandleException("未找到该考勤机");
        }
        // 适配范围变更
        UpdateChangeDto updateChange = ruleScopeUtil.updateRuleScopeList(machineManage.getId(), ConstantUtil.SCOPE_ORG_USER, ConstantUtil.SCOPE_ORG_USER,
                MutablePair.of(List.of(), List.of()), ScopeBizType.ATTENDANCE_MACHINE);
        // 需要删除的
        List<UserBoundVO> delUserList = getOrgUserList(updateChange.getDelOrgList());
        List<String> delUserIds = delUserList.stream().map(UserBoundVO::getId).collect(Collectors.toList());
        delUserIds.addAll(updateChange.getDelUserList());
        if (!delUserIds.isEmpty()) {
            // 从考勤机中移除
            attenceMachineService.deleteUserList(machineManage.getType(), machineManage.getMac(), delUserIds);
        }
        // 数据库操作
        machineManage.setDeleteMark(ConstantUtil.NUM_TRUE);
        machineManage.setDeleteTime(new Date());
        machineManage.setDeleteUserId(UserProvider.getUser().getUserId());
        attendanceMachineManageMapper.updateById(machineManage);
        // 移除redis考勤机租户关系
        redisUtil.removeHash(ConstantUtil.DEVICE_TENANT, machineManage.getMac());
    }

    @Override
    public List<GroupUserMiniVo> getGroupUserList(String groupId) {

        List<GroupUserMiniVo> returnList = new ArrayList<>();
        DateDetail dateDetail = new DateDetail();
        Date end = dateDetail.getCurrentDate();
        Date start = dateDetail.addNum(dateDetail.getCurrentDate(), -2, Calendar.MONTH);
        List<AttendanceGroupUser> groupUserList = attendanceUserService.getAttendanceGroupUsersOfSecondment(start, end, List.of(), List.of(groupId));
        List<String> userIds = groupUserList.stream().map(AttendanceGroupUser::getUserId).collect(Collectors.toList());
        if (!userIds.isEmpty()) {
            // 查询人脸信息
            Map<String, AttendanceUserFace> faceMap = getFaceMap(userIds);
            // 查询用户信息
            ActionResult<List<UserBoundVO>> userList = v2UserApi.getAllUserInfoBatch(userIds, null);
            Map<String, UserBoundVO> userMap = new HashMap<>();
            if (200 == userList.getCode() && CollectionUtil.isNotEmpty(userList.getData())) {
                userMap = userList.getData().stream().collect(Collectors.toMap(UserBoundVO::getId, Function.identity())) ;
            }
            Map<String, UserBoundVO> finalUserMap = userMap;
            userIds.forEach(userId -> {
                AttendanceUserFace userFace = faceMap.get(userId);
                UserBoundVO userBoundVO = finalUserMap.get(userId);
                GroupUserMiniVo mini = new GroupUserMiniVo(userId, userBoundVO == null ? "--" : userBoundVO.getUserName(), userFace == null ? "" : userFace.getFaceData());
                returnList.add(mini);
            });
        }
        return returnList;
    }

    private Map<String, AttendanceUserFace> getFaceMap(List<String> userIds) {

        LambdaQueryWrapper<AttendanceUserFace> faceQuery = new LambdaQueryWrapper<AttendanceUserFace>()
                .in(AttendanceUserFace::getUserId, userIds)
                .eq(AttendanceUserFace::getDeleteMark, ConstantUtil.NUM_FALSE);
        List<AttendanceUserFace> faceList = attendanceUserFaceMapper.selectList(faceQuery);
        return faceList.stream().collect(Collectors.toMap(AttendanceUserFace::getUserId, Function.identity()));
    }

    @Override
    public List<GroupUserMiniVo> getMachineMemberList(String id) {

        return null;
    }

    @Override
    public PageInfo<LogMiniVo> getLogList(String id, PageDto pageQuery) {

        // 查询考勤机信息
        AttendanceMachineManage machineManage = attendanceMachineManageMapper.selectById(id);
        if (null == machineManage) {
            return new PageInfo<>();
        }
        // 查询3个月的打卡记录
        DateDetail dateDetail = new DateDetail();
        Date date = dateDetail.addNum(null, -3, Calendar.MONTH);
        PageHelper.startPage(pageQuery.getCurrentPage(), pageQuery.getPageSize());
        return new PageInfo<>(attendanceMachineLogMapper.getLogList(ActionEnum.DA_KA.getDescription(), date, machineManage.getMac()));
    }

    @Override
    public List<GroupUserMiniVo> syncMachineMemberData(String id) {

        // 查询考勤机信息
        AttendanceMachineManage machineManage = attendanceMachineManageMapper.selectById(id);
        if (null == machineManage || StringUtils.isEmpty(machineManage.getType())) {
            return new ArrayList<>();
        }
        List<GroupUserMiniVo> returnList = new ArrayList<>();
        LambdaQueryWrapper<AttendanceMachineSync> query = new LambdaQueryWrapper<AttendanceMachineSync>()
                .eq(AttendanceMachineSync::getMac, machineManage.getMac());
        List<AttendanceMachineSync> list = attendanceMachineSyncService.list(query);
        if (!list.isEmpty()) {
            List<String> userIds = list.stream().map(AttendanceMachineSync::getUserId).collect(Collectors.toList());
            // 查询人脸数据
            Map<String, AttendanceUserFace> faceMap = getFaceMap(userIds);
            list.forEach(v -> {
                AttendanceUserFace userFace = faceMap.get(v.getUserId());
                GroupUserMiniVo user = new GroupUserMiniVo(v.getUserId(), v.getUserName(), null == userFace ? "" : userFace.getFaceData());
                returnList.add(user);
            });
        }
        return returnList;
    }

    @Override
    public MachineScopeVo getUpdateDetail(String id) {

        AttendanceMachineManage machine = attendanceMachineManageMapper.selectById(id);
        MachineScopeVo machineScope = JsonUtil.getJsonToBean(machine, MachineScopeVo.class);
        MutablePair<List<String>, List<String>> pair = ruleScopeUtil.selectScopeList(id, ScopeBizType.ATTENDANCE_MACHINE);
        machineScope.setOrganizeList(pair.getLeft());
        machineScope.setUserIdList(pair.getRight());
        return machineScope;
    }
}
