package jnpf.attendance.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import jnpf.attendance.mapper.AttendanceLocationSettingMapper;
import jnpf.attendance.mapper.AttendanceMachineManageMapper;
import jnpf.attendance.service.AttenceMachineService;
import jnpf.attendance.service.AttendanceGroupService;
import jnpf.attendance.service.AttendanceLocationSettingService;
import jnpf.base.ActionResult;
import jnpf.base.UserInfo;
import jnpf.base.service.SuperServiceImpl;
import jnpf.entity.AttendanceGroup;
import jnpf.entity.attendance.AttendanceBaseSetting;
import jnpf.entity.attendance.AttendanceLocationSetting;
import jnpf.entity.attendance.AttendanceMachineManage;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.AttendanceLocationSettingDto;
import jnpf.model.attendance.dto.SaveForStoreDto;
import jnpf.model.attendance.vo.AttendanceGroupVo;
import jnpf.model.attendance.vo.AttendanceLocationSettingVo;
import jnpf.permission.StoreApi;
import jnpf.permission.V2OrganizeApi;
import jnpf.permission.dto.store.QueryStoreListDTO;
import jnpf.permission.vo.store.StoreBaseListInfo;
import jnpf.permission.vo.v2.organzie.OrganizeGeneralDetailVO;
import jnpf.util.ConstantUtil;
import jnpf.util.RandomUtil;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 考勤组-考勤点配置表 服务实现类
 * </p>
 *
 * @author ahua
 * @since 2023-11-29
 */
@Service
public class AttendanceLocationSettingServiceImpl extends SuperServiceImpl<AttendanceLocationSettingMapper, AttendanceLocationSetting> implements AttendanceLocationSettingService {

    @Autowired
    private AttendanceGroupService attendanceGroupService;
    @Autowired
    private AttendanceMachineManageMapper attendanceMachineManageMapper;
    @Autowired
    private AttenceMachineService attenceMachineService;
    @Autowired
    private StoreApi storeApi;
    @Override
    public List<AttendanceLocationSettingVo> findList(String groupId, Integer type) {
        Map<String, List<AttendanceLocationSetting>> enableLocationSetting = getEnableLocationSetting(CollUtil.newArrayList(groupId));
        List<AttendanceLocationSetting> orDefault = enableLocationSetting.getOrDefault(groupId, CollUtil.newArrayList());
        if (CollUtil.isEmpty(orDefault)) {
            return CollUtil.newArrayList();
        }
        return orDefault.stream()
                .filter(location -> Objects.equals(location.getType(), type))
                .map(entity -> BeanUtil.toBean(entity, AttendanceLocationSettingVo.class))
                .collect(Collectors.toList());

    }

    @Override
    public void saveForStore(SaveForStoreDto saveForStore) {
        Assert.isFalse(CollUtil.isEmpty(saveForStore.getStoreIds()), "未查询到所选门店信息");
        List<StoreBaseListInfo> storeList = storeApi.listInfo(new QueryStoreListDTO() {{
            setIds(saveForStore.getStoreIds());
        }}).getData();
        Assert.isFalse(CollUtil.isEmpty(storeList), "未查询到所选门店信息");
        Date date = new Date();
        String loginUserId = UserProvider.getLoginUserId();
        List<AttendanceLocationSetting> collect = storeList.stream().map(store -> {
            AttendanceLocationSetting attendanceLocationSetting = new AttendanceLocationSetting();
            attendanceLocationSetting.setId(RandomUtil.uuId());
            attendanceLocationSetting.setEnable(1);
            attendanceLocationSetting.setType(1);
            attendanceLocationSetting.setGroupId(saveForStore.getGroupId());
            attendanceLocationSetting.setName(store.getStoreName());
            attendanceLocationSetting.setAddress(store.getAddress());
            attendanceLocationSetting.setLat(store.getLatitude());
            attendanceLocationSetting.setLng(store.getLongitude());
            attendanceLocationSetting.setClockRange(saveForStore.getClockRange());
            attendanceLocationSetting.setDeleteMark(0);
            attendanceLocationSetting.setCreatorTime(date);
            attendanceLocationSetting.setCreatorUserId(loginUserId);
            attendanceLocationSetting.setStoreId(store.getId());
            return attendanceLocationSetting;
        }).collect(Collectors.toList());
        saveBatch(collect);
    }
    @Override
    public void delForStore(SaveForStoreDto saveForStore) {
        Assert.isFalse(CollUtil.isEmpty(saveForStore.getStoreIds()), "未查询到所选门店信息");
        lambdaUpdate().set(AttendanceLocationSetting::getDeleteMark, 1)
                .set(AttendanceLocationSetting::getDeleteTime, new Date())
                .set(AttendanceLocationSetting::getDeleteUserId, UserProvider.getLoginUserId())
                .eq(AttendanceLocationSetting::getGroupId, saveForStore.getGroupId())
                .in(AttendanceLocationSetting::getStoreId, saveForStore.getStoreIds())
                .update();
    }

    @Override
    public List<String> getStoreIds(String groupId) {
        List<AttendanceLocationSetting> list = lambdaQuery().select(AttendanceLocationSetting::getStoreId).eq(AttendanceLocationSetting::getGroupId, groupId)
                .eq(AttendanceLocationSetting::getType, 1)
                .isNotNull(AttendanceLocationSetting::getStoreId)
                .eq(AttendanceLocationSetting::getDeleteMark, 0)
                .list();
        return list.stream().map(AttendanceLocationSetting::getStoreId).collect(Collectors.toList());
    }

    @Override
    public void save(AttendanceLocationSettingDto dto) throws HandleException {
        AttendanceLocationSetting entity = BeanUtil.toBean(dto, AttendanceLocationSetting.class);
        UserInfo user = UserProvider.getUser();
        List<AttendanceGroup> attendanceGroups = attendanceGroupService.queryListByIds(CollUtil.newArrayList(dto.getGroupId()));
        if (CollUtil.isEmpty(attendanceGroups)) {
            throw new HandleException("当前考勤组未查到");
        }
        AttendanceGroup attendanceGroup = attendanceGroups.get(0);
        Integer enable;
        if (dto.getType() == 1) {
            enable = attendanceGroup.getGpsEnable();
        } else if (dto.getType() == 2) {
            enable = attendanceGroup.getWifiEnable();
        } else {
            enable = attendanceGroup.getMachineEnable();
        }
        if (StringUtil.isEmpty(entity.getId())) {
            entity.setCreatorTime(new Date());
            entity.setCreatorUserId(user.getUserId());
            entity.setTenantId(user.getTenantId());
            entity.setEnable(enable);
            entity.setDeleteMark(0);
        } else {
            entity.setLastModifyTime(new Date());
            entity.setLastModifyUserId(user.getUserId());
            entity.setEnable(enable);
            entity.setDeleteMark(0);
        }
        saveOrUpdate(entity);
        if (Objects.equals(dto.getType(), 3) && StringUtil.isEmpty(dto.getId())) {
            sendUserToMachine(dto.getFactoryCode(), dto.getAddress(), dto.getGroupId());
        }
    }

    @Override
    public void sendSingleUserToMachine(String groupId, String userId) {
        List<AttendanceLocationSetting> list = lambdaQuery().eq(AttendanceLocationSetting::getGroupId, groupId)
                .eq(AttendanceLocationSetting::getType, 3)
                .eq(AttendanceLocationSetting::getDeleteMark, Boolean.FALSE)
                .list();
        if (CollUtil.isEmpty(list)) {
            return;
        }
        list.forEach(location -> {
            sendUserToMachine(location.getFactoryCode(), location.getAddress(), CollUtil.newArrayList(userId));
        });
    }

    /**
     * 批量删除设备人员
     *
     * @param groupId 考勤组id
     * @param userId  用户id
     */
    @Override
    public void deleteUserToMachine(String groupId, String userId) {
        List<AttendanceLocationSetting> list = lambdaQuery().eq(AttendanceLocationSetting::getGroupId, groupId)
                .eq(AttendanceLocationSetting::getType, 3)
                .eq(AttendanceLocationSetting::getDeleteMark, Boolean.FALSE)
                .list();
        if (CollUtil.isEmpty(list)) {
            return;
        }
        list.forEach(location -> attenceMachineService.deleteUserList(location.getFactoryCode(), location.getAddress(), CollUtil.newArrayList(userId)));
    }

    private void sendUserToMachine(String factoryCode, String sn, String groupId) {
        // List<AttendanceGroupUser> attendanceGroupUsers = attendanceUserService.queryByUsersGroupIds(CollUtil.newArrayList(groupId));
        // List<String> collect = attendanceGroupUsers.stream().map(AttendanceGroupUser::getUserId).collect(Collectors.toList());
        List<String> userIds = attendanceGroupService.getSelfAndChildrenMembers(groupId);
        sendUserToMachine(factoryCode, sn, userIds);
    }

    private void sendUserToMachine(String factoryCode, String sn, List<String> userIds) {
        if (userIds.isEmpty()) {
            return;
        }
        userIds.forEach(userId -> {
            attenceMachineService.sendUserToMachine(factoryCode, userId, sn);
        });
    }

    /**
     * 删除人员
     *
     * @param factoryCode 厂商编码
     * @param sn          设备号
     * @param groupId     考勤组id
     */
    private void deleteUserToMachineByGroupId(String factoryCode, String sn, String groupId) {
        /*List<AttendanceGroupUser> attendanceGroupUsers = attendanceUserService.queryByUsersGroupIds(CollUtil.newArrayList(groupId));
        List<String> userIds = attendanceGroupUsers.stream().map(AttendanceGroupUser::getUserId).collect(Collectors.toList());*/
        List<String> userIds = attendanceGroupService.getSelfAndChildrenMembers(groupId);
        if (!userIds.isEmpty()) {
            attenceMachineService.deleteUserList(factoryCode, sn, userIds);
        }
    }

    @Override
    @Transactional
    public void initLocationSetting(String groupId) {
        List<AttendanceLocationSetting> list = lambdaQuery().eq(AttendanceLocationSetting::getGroupId, groupId)
                .eq(AttendanceLocationSetting::getDeleteMark, Boolean.FALSE)
                .list();
        if (CollUtil.isNotEmpty(list)) {
            return;
        }

        Map<String, List<AttendanceLocationSetting>> enableBaseSetting = getEnableLocationSetting(CollUtil.newArrayList(groupId));
        List<AttendanceLocationSetting> attendanceLocationSettings = enableBaseSetting.get(groupId);
        AttendanceGroup byId = attendanceGroupService.getById(groupId);
        if (CollUtil.isNotEmpty(attendanceLocationSettings)) {
            AttendanceLocationSetting attendanceLocationSetting1 = attendanceLocationSettings.stream().findFirst().orElse(null);
            AttendanceGroup byId1 = null;
            if (attendanceLocationSetting1 != null) {
                byId1 = attendanceGroupService.getById(attendanceLocationSetting1.getGroupId());
            }
            byId.setGpsEnable(byId1.getGpsEnable());
            byId.setWifiEnable(byId1.getWifiEnable());
            byId.setMachineEnable(byId1.getMachineEnable());
            attendanceGroupService.updateById(byId);
            attendanceLocationSettings.forEach(attendanceLocationSetting -> {
                attendanceLocationSetting.setId(RandomUtil.uuId());
                attendanceLocationSetting.setGroupId(groupId);
                attendanceLocationSetting.setCreatorTime(new Date());
                attendanceLocationSetting.setCreatorUserId(UserProvider.getLoginUserId());
            });
        }
        //初始化组织配置地址至考勤组
        ActionResult<StoreBaseListInfo> info = storeApi.info(byId.getOrgId());
        if (Objects.isNull(info) || Objects.isNull(info.getData())){
            if (CollUtil.isEmpty(attendanceLocationSettings)){
                return;
            }
            saveBatch(attendanceLocationSettings);
            return;
        }
        if(Objects.isNull(attendanceLocationSettings)){
            attendanceLocationSettings = Lists.newArrayList();
        }
        StoreBaseListInfo data = info.getData();
        AttendanceLocationSetting attendanceLocationSetting = new AttendanceLocationSetting();
        attendanceLocationSetting.setGroupId(groupId);
        attendanceLocationSetting.setName(data.getStoreName());
        attendanceLocationSetting.setAddress(data.getAddress());
        attendanceLocationSetting.setLat(data.getLatitude());
        attendanceLocationSetting.setLng(data.getLongitude());
        attendanceLocationSetting.setType(1);
        attendanceLocationSetting.setClockRange(100);
        attendanceLocationSetting.setEnable(1);
        attendanceLocationSetting.setId(RandomUtil.uuId());
        attendanceLocationSetting.setCreatorTime(new Date());
        attendanceLocationSetting.setCreatorUserId(UserProvider.getLoginUserId());
        attendanceLocationSetting.setDeleteMark(0);
        attendanceLocationSetting.setStoreId(byId.getOrgId());
        attendanceLocationSettings.add(attendanceLocationSetting);
        saveBatch(attendanceLocationSettings);
    }

    @Override
    public Map<String, List<AttendanceLocationSetting>> getEnableLocationSetting(List<String> groupIds) {
        List<AttendanceGroup> attendanceGroupVos = attendanceGroupService.queryDropList();
        if (CollUtil.isEmpty(attendanceGroupVos)) {
            log.error("未查询到考勤组信息");
            return Maps.newHashMap();
        }
        Map<String, String> groupIdToParent = attendanceGroupVos.stream().collect(Collectors.toMap(AttendanceGroup::getId, groupVo -> StringUtil.isBlank(groupVo.getParentId()) ? "-1" : groupVo.getParentId()));
        Map<String, Boolean> collect1 = attendanceGroupVos.stream().collect(Collectors.toMap(AttendanceGroup::getId, group -> group.getAttendancePointsSetting() == 1));
        List<AttendanceLocationSetting> list = lambdaQuery()
                .eq(AttendanceLocationSetting::getDeleteMark, Boolean.FALSE)
                .ne(AttendanceLocationSetting::getType, ConstantUtil.DEVICE_MACHINE)
                .list();
        Map<String, List<AttendanceLocationSetting>> collect = list.stream().filter(base -> collect1.getOrDefault(base.getGroupId(), Boolean.FALSE)).collect(Collectors.groupingBy(AttendanceLocationSetting::getGroupId));
        collect1.forEach((groupId, enable) -> {
            if (enable && !collect.containsKey(groupId)) {
                collect.put(groupId, CollUtil.newArrayList());
            }
        });
        // 根据groupIds查询考勤机管理的考勤机
        for (String groupId : groupIds) {
            List<AttendanceMachineManage> machineList = attendanceMachineManageMapper.getRelationMachineByGroupId(groupId);
            List<AttendanceLocationSetting> mList = changeToLocation(groupId, machineList);
            if (!machineList.isEmpty()) {
                collect.compute(groupId, (k, v) -> {
                    if (v == null) {
                        return mList;
                    } else {
                        v.addAll(mList);
                        return v;
                    }
                });
            }
        }
        Map<String, List<AttendanceLocationSetting>> map = Maps.newHashMap();
        groupIds.forEach(groupId -> map.put(groupId, findNextBaseSetting(collect, groupIdToParent, groupId)));
        return map;
    }

    private List<AttendanceLocationSetting> changeToLocation(String groupId, List<AttendanceMachineManage> machineList) {

        List<AttendanceLocationSetting> list = new ArrayList<>();
        machineList.forEach(machine -> list.add(new AttendanceLocationSetting(machine.getId(), groupId, machine.getName(), machine.getMac(), machine.getType())));
        return list;
    }

    @Override
    public List<AttendanceGroupVo> getEnableGroup(String groupId) {
        List<AttendanceGroup> attendanceGroupVos = attendanceGroupService.queryDropList();
        if (CollUtil.isEmpty(attendanceGroupVos)) {
            log.error("未查询到考勤组信息");
            return CollUtil.newArrayList();
        }
        AttendanceGroup attendanceGroup = attendanceGroupVos.stream().filter(group -> StringUtil.equals(group.getId(), groupId)).reduce((g1, g2) -> g1).orElse(null);
        if (attendanceGroup != null && Objects.equals(attendanceGroup.getAttendancePointsSetting(), 0)) {
            log.error("当前考勤组未开启考勤点配置");
            return CollUtil.newArrayList();
        }
        Map<String, List<AttendanceGroup>> groupIdToParent = attendanceGroupVos.stream().collect(Collectors.groupingBy(AttendanceGroup::getParentId));
        List<AttendanceGroupVo> groupVos = CollUtil.newArrayList();
        List<AttendanceGroup> orDefault = groupIdToParent.getOrDefault(groupId, CollUtil.newArrayList());
        if (CollUtil.isEmpty(orDefault)) {
            return CollUtil.newArrayList();
        }
        getEnableSingleGroup(orDefault, groupVos, groupIdToParent);
        return groupVos;
    }

    private void getEnableSingleGroup(List<AttendanceGroup> groups, List<AttendanceGroupVo> groupVos, Map<String, List<AttendanceGroup>> groupIdToParent) {
        groups.forEach(group -> {
            if (Objects.equals(group.getAttendancePointsSetting(), 1)) {
                return;
            }
            groupVos.add(BeanUtil.toBean(group, AttendanceGroupVo.class));
            List<AttendanceGroup> attendanceGroups = groupIdToParent.get(group.getId());
            if (CollUtil.isEmpty(attendanceGroups)) {
                return;
            }
            getEnableSingleGroup(attendanceGroups, groupVos, groupIdToParent);
        });
    }

    private List<AttendanceLocationSetting> findNextBaseSetting(Map<String, List<AttendanceLocationSetting>> collect, Map<String, String> groupIdToParent, String groupId) {
        if (StringUtil.isBlank(groupId)) {
            return CollUtil.newArrayList();
        }
        if (!collect.containsKey(groupId)) {
            return findNextBaseSetting(collect, groupIdToParent, groupIdToParent.get(groupId));
        }
        return collect.get(groupId);
    }

    @Override
    public void del(String id) {
        lambdaUpdate().set(AttendanceLocationSetting::getDeleteMark, Boolean.TRUE)
                .set(AttendanceLocationSetting::getDeleteUserId, UserProvider.getLoginUserId())
                .set(AttendanceLocationSetting::getDeleteTime, new Date())
                .eq(AttendanceLocationSetting::getId, id)
                .update();
        AttendanceLocationSetting byId = getById(id);
        if (Objects.equals(byId.getType(), 3)) {
            deleteUserToMachineByGroupId(byId.getFactoryCode(), byId.getAddress(), byId.getGroupId());
        }
    }

    @Override
    public void changeStatus(String groupId, Integer type, Integer enable) {
        lambdaUpdate().set(AttendanceLocationSetting::getEnable, enable)
                .eq(AttendanceLocationSetting::getGroupId, groupId)
                .eq(AttendanceLocationSetting::getType, type)
                .update();
    }

    @Override
    public void hisLocationSetting(Map<String, String> group2orgMap, Map<String, String> org2groupMap) {
        List<AttendanceLocationSetting> list = lambdaQuery().eq(AttendanceLocationSetting::getDeleteMark, Boolean.FALSE).list();
        list.forEach(item->item.setGroupId(org2groupMap.getOrDefault(group2orgMap.getOrDefault(item.getGroupId(),item.getGroupId()),item.getGroupId())));
        AtomicInteger i = new AtomicInteger(0);
        list.stream().collect(Collectors.groupingBy(vo -> vo.getGroupId() + vo.getType() + vo.getName())).forEach((vo,settings)->{
            i.set(0);
            settings.stream().skip(1).forEach(setting->setting.setName(setting.getName()+i.incrementAndGet()));
        });
        updateBatchById(list);
    }
}
