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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.json.JSONObject;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.infra.api.file.FileApi;
import cn.iocoder.yudao.module.infra.api.websocket.WebSocketSenderApi;
import cn.iocoder.yudao.module.system.controller.admin.equipment.vo.userExt.UserExtImportVO;
import cn.iocoder.yudao.module.system.controller.admin.equipment.vo.userExt.UsersExtPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.equipment.vo.userExt.UsersExtRespVO;
import cn.iocoder.yudao.module.system.controller.admin.equipment.vo.userExt.UsersExtSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.equipment.vo.websocket.DeleteUserVO;
import cn.iocoder.yudao.module.system.controller.admin.equipment.vo.websocket.UpdateFaceImgVO;
import cn.iocoder.yudao.module.system.controller.admin.equipment.vo.websocket.WebsocketBaseVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserImportRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.equipment.DistributeRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.equipment.UsersExtDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.equipment.UsersExtMapper;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import cn.iocoder.yudao.module.system.service.websocket.WebsocketService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.github.yulichang.toolkit.SpringContentUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

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.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;

/**
 * 用户信息拓展 Service 实现类
 *
 * @author 符溶馨
 */
@Service
@Validated
public class UsersExtServiceImpl implements UsersExtService {

    @Resource
    private UsersExtMapper usersExtMapper;

    @Resource
    @Lazy
    private DeptService deptService;

    @Resource
    @Lazy
    private FileApi fileApi;

    @Resource
    private AdminUserService userService;

    @Resource
    private WebSocketSenderApi webSocketSenderApi;

    @Resource
    private DistributeRecordService recordService;

    @Resource
    private WebsocketService websocketService;

    @Override
    public void createUsers(UsersExtSaveReqVO createReqVO) {

        if (usersExtMapper.selectCount(UsersExtDO::getUserId, createReqVO.getUserId()) > 0L) {

            throw exception(USERS_EXT_EXISTS);
        }

        UsersExtDO usersExtDO = BeanUtils.toBean(createReqVO, UsersExtDO.class);
        usersExtMapper.insert(usersExtDO);
    }

    @Override
    public String createUsersExt(UsersExtDO updateDO, MultipartFile file) throws IOException {

        String url = null;
        String name = null;
        String fileName = file.getOriginalFilename();
        if (fileName == null || fileName.isEmpty()) {

            name = updateDO.getUserId() + "_faceImg.jpg";
        }else {

            name = updateDO.getUserId() + "_faceImg." + fileName.split("\\.")[1];
        }
        byte[] content = IoUtil.readBytes(file.getInputStream());

        //校验 当前用户人脸信息是否已存在
        UsersExtDO usersExtDO = usersExtMapper.selectOne(UsersExtDO::getUserId, updateDO.getUserId());
        if (usersExtDO == null) {

            // 同步 把人脸图片插入 BusinessFile中 存储文件
            url = fileApi.createBusinessFile(6L, name, content) ;

            updateDO.setFaceImg(url);
            usersExtMapper.insert(updateDO);

        }else {

            //有人脸图片的情况
            if (StringUtils.isNotEmpty(usersExtDO.getFaceImg())) {

                // 变更business_file的content字段内容
                url = fileApi.updateBusinessFileContent(usersExtDO.getFaceImg(), 6L, name, content);

//                //更新人脸图片
//                updateDO.setId(usersExtDO.getId());
//                updateDO.setFaceImg(url);
//                usersExtMapper.updateById(usersExtDO);
            }else {

                // 同步 把人脸图片插入 BusinessFile中 存储文件
                url = fileApi.createBusinessFile(6L, name, content) ;

                //更新人脸图片
                usersExtMapper.updateById(new UsersExtDO()
                        .setId(usersExtDO.getId())
                        .setFaceImg(url));
            }

            // 判断用户是否已下发至考勤设备
            if (usersExtDO.getAttendanceMachineNos() != null) {

                String requestId = IdWorker.get32UUID();
                WebsocketBaseVO baseVO = new WebsocketBaseVO()
                        .setFrom("")
                        .setExtra(requestId + "_" + getLoginUserId());
                for (String deviceNo : usersExtDO.getAttendanceMachineNos()) {

                    // 设备指令信息
                    UpdateFaceImgVO faceImgVO = new UpdateFaceImgVO();
                    faceImgVO.setUser_id(String.valueOf(usersExtDO.getUserId()));
                    faceImgVO.setFace_template(url);

                    baseVO.setTo(deviceNo);
                    baseVO.setData(faceImgVO);

                    // 设置 设备下发记录
                    DistributeRecordDO recordDO = new DistributeRecordDO();
                    recordDO.setRequestId(requestId);
                    recordDO.setDeviceNo(deviceNo);
                    recordDO.setUserId(usersExtDO.getUserId());
                    recordDO.setType(2);
                    recordDO.setResult("通讯失败");

                    // 更新下发记录信息
                    recordService.createDistributeRecord(Collections.singletonList(recordDO));

                    // 设备租户ID
                    TenantContextHolder.setTenantId(1L);
                    // 发送指令至设备 更新设备上人脸图片
                    webSocketSenderApi.sendSN(deviceNo, "attendance-message-send", JsonUtils.toJsonString(baseVO));
                }
            }
        }

        // 返回
        return url;
    }

    @Override
    public void updateUsersExt(UsersExtSaveReqVO updateReqVO) {
        // 校验存在
        validateUsersExtExists(updateReqVO.getUserId());
        // 更新
        UsersExtDO updateObj = BeanUtils.toBean(updateReqVO, UsersExtDO.class);

        usersExtMapper.updateById(updateObj);
    }

    @Override
    public void updateUser(UsersExtSaveReqVO updateReqVO) {

        // 校验存在
        validateUsersExtExists(updateReqVO.getUserId());

        // 更新
        UsersExtDO updateObj = BeanUtils.toBean(updateReqVO, UsersExtDO.class);

        usersExtMapper.update(updateObj,
                new LambdaQueryWrapperX<UsersExtDO>().eq(UsersExtDO::getUserId, updateReqVO.getUserId()));
    }

    @Override
    public void updateListUsersExt(List<UsersExtDO> updateDo) {

        // 更新
        usersExtMapper.updateBatch(updateDo);
    }

    @Override
    public void deleteUser(Long userId) {

        //校验 当前用户人脸信息是否已存在
        UsersExtDO usersExtDO = usersExtMapper.selectOne(UsersExtDO::getUserId, userId);
        List<String> deviceNos = new ArrayList<>();
        if (usersExtDO != null) {

            deviceNos = usersExtDO.getAttendanceMachineNos();
            usersExtMapper.delete(UsersExtDO::getUserId, userId);
        }

        if (deviceNos != null && !deviceNos.isEmpty()) {

            DeleteUserVO userVO = new DeleteUserVO()
                    .setCmd("delMultiUser")
                    .setUser_ids(new String[]{String.valueOf(usersExtDO.getUserId())});

            // 删除的用户Id 存在redis中
            StringRedisTemplate redisTemplate = SpringContentUtils.getBean(StringRedisTemplate.class);
            for (String deviceNo : deviceNos) {

                redisTemplate.opsForValue().set(deviceNo, new JSONObject(userVO).get("user_ids").toString());
                websocketService.sendSn(deviceNo, userVO, 0);
            }
        }
    }

    private void validateUsersExtExists(Long userId) {

        if (usersExtMapper.selectOne(UsersExtDO::getUserId, userId) == null) {
            throw exception(USERS_EXT_NOT_EXISTS);
        }
    }

    @Override
    public UsersExtDO getUsersExt(Long id) {

        return usersExtMapper.selectById(id);
    }

    @Override
    public UsersExtDO getUsersExtByUserId(Long userId) {

        return usersExtMapper.selectOne(UsersExtDO::getUserId, userId);
    }

    @Override
    public List<UsersExtDO> getListByUserId(List<Long> userId) {

        return usersExtMapper.selectList(UsersExtDO::getUserId, userId);
    }

    @Override
    public PageResult<UsersExtRespVO> getUsersExtPage(UsersExtPageReqVO pageReqVO) {

        if (pageReqVO.getDeptId() != null) {

            List<Long> deptIds = convertList(deptService.getChildDeptList(pageReqVO.getDeptId()), DeptDO::getId);
            deptIds.add(pageReqVO.getDeptId()); // 包括自身

            pageReqVO.setDeptIds(deptIds);
        }

        IPage<UsersExtRespVO> mpPage = MyBatisUtils.buildPage(pageReqVO);
        IPage<UsersExtRespVO> page = usersExtMapper.selectFacePage(mpPage, pageReqVO);

        return new PageResult<>(page.getRecords(), page.getTotal());
    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 添加事务，异常则回滚所有导入
    public UserImportRespVO importUserList(List<UserExtImportVO> importUsers, Boolean isUpdateSupport) {

        if (CollUtil.isEmpty(importUsers)) {
            throw exception(USER_IMPORT_LIST_IS_EMPTY);
        }

        UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>()).updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build();

        Map<Long, AdminUserDO> userDOMap = userService.getUserMap(convertList(importUsers, UserExtImportVO::getUserId));

        importUsers.forEach(importUser -> {

            if (importUser.getFaceFile() == null) {
                return;
            }

            //获得 更新信息
            UsersExtDO updateDO = BeanUtils.toBean(importUser, UsersExtDO.class);
            //设备部门编号
            updateDO.setDeptId(userDOMap.get(updateDO.getUserId()).getDeptId());

            String url = null;
            String name = null;
            name = importUser.getUserId() + "_faceImg.jpg";

            //校验 当前用户人脸信息是否已存在
            UsersExtDO usersExtDO = usersExtMapper.selectOne(UsersExtDO::getUserId, importUser.getUserId());
            if (usersExtDO == null) {

                // 同步 把人脸图片插入 BusinessFile中 存储文件
                url = fileApi.createBusinessFile(6L, name, importUser.getFaceFile());

                updateDO.setFaceImg(url);
                usersExtMapper.insert(updateDO);

                respVO.getCreateUsernames().add(importUser.getUserName());
            } else {

                if (!isUpdateSupport) {

                    respVO.getFailureUsernames().put(importUser.getUserName(), USERS_FACE_EXISTS.getMsg());
                } else {

                    // 变更business_file的content字段内容
                    url = fileApi.updateBusinessFileContent(usersExtDO.getFaceImg(), 6L, name, importUser.getFaceFile());

                    //更新人脸图片
                    updateDO.setId(usersExtDO.getId());
                    updateDO.setFaceImg(url);
                    usersExtMapper.updateById(updateDO);

                    respVO.getUpdateUsernames().add(importUser.getUserName());
                }
            }
        });

        return respVO;
    }
}