package cn.iocoder.yudao.module.system.service.equipment;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.module.system.controller.admin.assets.vo.DeptAssetsInOutStockSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.equipment.vo.attendancemachine.*;
import cn.iocoder.yudao.module.system.controller.admin.equipment.vo.userExt.UsersExtRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.assets.AssetsTypeDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.equipment.AttendanceMachineDO;
import cn.iocoder.yudao.module.system.dal.dataobject.equipment.UsersExtDO;
import cn.iocoder.yudao.module.system.dal.mysql.equipment.AttendanceMachineMapper;
import cn.iocoder.yudao.module.system.service.assets.AssetsTypeService;
import cn.iocoder.yudao.module.system.service.assets.DeptAssetsInOutStockService;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;

/**
 * 考勤设备 Service 实现类
 *
 * @author 符溶馨
 */
@Service
@Validated
public class AttendanceMachineServiceImpl implements AttendanceMachineService {

    @Resource
    private AttendanceMachineMapper attendanceMachineMapper;

    @Resource
    private AssetsTypeService assetsTypeService;

    @Resource
    private DeptService deptService;

    @Resource
    private DeptAssetsInOutStockService deptAssetsInOutStockService;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private UsersExtService usersExtService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createAttendanceMachine(AttendanceMachineSaveReqVO createReqVO) {
        // 插入
        AttendanceMachineDO attendanceMachine = BeanUtils.toBean(createReqVO, AttendanceMachineDO.class);

        //如果分配机构的情况， 则调用资产分配方法
        if (createReqVO.getDeptId() != null) {

            DeptAssetsInOutStockSaveReqVO vos = new DeptAssetsInOutStockSaveReqVO();
            vos.setInDeptId(createReqVO.getDeptId());
            vos.setAssetsId(createReqVO.getAssetsId());
            vos.setNum(1);

            deptAssetsInOutStockService.createDeptAssetsInOutStock(-1L, Collections.singletonList(vos));
        }

        //设置设备初始密码
        attendanceMachine.setPassword(passwordEncoder.encode("123456"));
        attendanceMachineMapper.insert(attendanceMachine);
        // 返回
        return attendanceMachine.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAttendanceMachine(AttendanceMachineSaveReqVO updateReqVO) {

        // 校验存在
        validateAttendanceMachineExists(updateReqVO.getId(), updateReqVO.getDeviceNo());

        //如果分配机构的情况， 则调用资产分配方法
        if (updateReqVO.getIsAssets()) {

            DeptAssetsInOutStockSaveReqVO vos = new DeptAssetsInOutStockSaveReqVO();
            vos.setInDeptId(updateReqVO.getDeptId());
            vos.setAssetsId(updateReqVO.getAssetsId());
            vos.setNum(1);

            deptAssetsInOutStockService.createDeptAssetsInOutStock(-1L, Collections.singletonList(vos));
        }

        // 更新
        AttendanceMachineDO updateObj = BeanUtils.toBean(updateReqVO, AttendanceMachineDO.class);
        attendanceMachineMapper.updateById(updateObj);
    }

    @Override
    public void updateAttendanceMachineStatus(List<DeviceStatusUpdateVO> statusUpdateVOS) {

        List<AttendanceMachineDO> updateDO = BeanUtils.toBean(statusUpdateVOS, AttendanceMachineDO.class);

        attendanceMachineMapper.updateBatch(updateDO);
    }

    @Override
    public void updatePassword(AttendanceMachinePasswordVO updateReqVO) {

        //校验 旧密码
        AttendanceMachineDO attendanceMachineDO = attendanceMachineMapper.selectOne(AttendanceMachineDO::getDeviceNo, updateReqVO.getDeviceNo());
        if (attendanceMachineDO == null) {

            throw exception(ATTENDANCE_MACHINE_NOT_EXISTS);
        } else {

            if (!passwordEncoder.matches(updateReqVO.getOldPassword(), attendanceMachineDO.getPassword())) {

                throw exception(ATTENDANCE_PASSWORD_NOT_EQUAL);
            }
        }

        //更新
        attendanceMachineDO = new AttendanceMachineDO()
                .setPassword(passwordEncoder.encode(updateReqVO.getNewPassword()));

        attendanceMachineMapper.update(attendanceMachineDO, new LambdaUpdateWrapper<AttendanceMachineDO>().eq(AttendanceMachineDO::getDeviceNo, updateReqVO.getDeviceNo()));
    }

    private void validateAttendanceMachineExists(Long id, String deviceNo) {

        if (attendanceMachineMapper.selectById(id) == null) {
            throw exception(ATTENDANCE_MACHINE_NOT_EXISTS);
        }

        if (attendanceMachineMapper.selectCount(AttendanceMachineDO::getDeviceNo, deviceNo) > 0L) {
            throw exception(DEVICE_NO_EXISTS);
        }
    }

    @Override
    public AttendanceMachineRespVO getAttendanceMachine(String assetsNo) {

        return attendanceMachineMapper.selectAttendanceByAssetsNo(assetsNo);
    }

    @Override
    public List<AttendanceMachineDO> getAttendanceMachineByDeviceNo(List<String> deviceNo) {

        return attendanceMachineMapper.selectList(AttendanceMachineDO::getDeviceNo, deviceNo);
    }

    @Override
    public PageResult<AttendanceMachineRespVO> getAttendanceMachinePage(AttendanceMachinePageReqVO pageReqVO) {

        //获得 设备资产编号
        AssetsTypeDO assetsTypeDO = assetsTypeService.getByName("考勤设备");
        if (assetsTypeDO != null) {

            pageReqVO.setTypeId(assetsTypeDO.getId());
        }

        IPage<AttendanceMachineRespVO> mpPage = MyBatisUtils.buildPage(pageReqVO);
        IPage<AttendanceMachineRespVO> page = attendanceMachineMapper.selectAttendancePage(mpPage, pageReqVO);

        // 获得部门信息Map
        Map<Long, DeptDO> deptDOMap = deptService.getDeptMap(convertList(page.getRecords(), AttendanceMachineRespVO::getDeptId));

        return new PageResult<>(
                CollectionUtils.convertList(page.getRecords(), data -> data.setDeptName(deptDOMap.isEmpty() || deptDOMap.get(data.getDeptId()) == null ? null : deptDOMap.get(data.getDeptId()).getName())),
                page.getTotal());
    }

    @Override
    public PageResult<UsersExtRespVO> getUserByDeviceNo(UserExtPageReqVO pageReqVO) {

        IPage<UsersExtRespVO> mpPage = MyBatisUtils.buildPage(pageReqVO);
        IPage<UsersExtRespVO> page = attendanceMachineMapper.selectUserPage(mpPage, pageReqVO);

        // 获得部门信息Map
        Map<Long, DeptDO> deptDOMap = deptService.getDeptMap(convertList(page.getRecords(), UsersExtRespVO::getDeptId));

        return new PageResult<>(
                CollectionUtils.convertList(page.getRecords(), data -> data.setDeptName(deptDOMap.isEmpty() || deptDOMap.get(data.getDeptId()) == null ? null : deptDOMap.get(data.getDeptId()).getName())),
                page.getTotal());
    }

    @Override
    public void addUserToAttendanceMachine(AddUserToAttendanceMachineVO addReqVO) {

        //获得 用户已绑定设备信息
        List<UsersExtDO> usersExtDO = usersExtService.getListByUserId(addReqVO.getUserId());

        // 更新用户已下发设备列表
        if (addReqVO.getMethod() == 0) {

            usersExtDO.forEach(data -> {

                List<String> deviceNo = data.getAttendanceMachineNos();

                // 添加不重复的设备号
                if (deviceNo == null || deviceNo.isEmpty()) {

                    deviceNo = new ArrayList<>();
                    deviceNo.add(addReqVO.getDeviceNo());
                } else {

                    if (!deviceNo.contains(addReqVO.getDeviceNo())) {

                        deviceNo.add(addReqVO.getDeviceNo());
                    }
                }

                //设备 用户绑定设备
                data.setAttendanceMachineNos(deviceNo);
            });
        } else if (addReqVO.getMethod() == 1) {

            usersExtDO.forEach(data -> {

                List<String> deviceNo = data.getAttendanceMachineNos();
                // 添加设备号
                deviceNo.remove(addReqVO.getDeviceNo());

                //设备 用户绑定设备
                data.setAttendanceMachineNos(deviceNo);
            });
        }

        // 更新 用户信息
        usersExtService.updateListUsersExt(usersExtDO);
    }

    @Override
    public List<AttendanceMachineDO> getListByStatus() {

        return attendanceMachineMapper.selectList();
    }

    @Override
    public List<AttendanceMachineDO> getListByDeptId(Long deptId) {

        return attendanceMachineMapper.selectList(AttendanceMachineDO::getDeptId, deptId);
    }
}