package com.zhongshu.card.server.core.service.projectAbout;

import com.github.microservice.auth.client.model.UserFaceConfidenceModel;
import com.github.microservice.auth.client.model.UserFaceUploadModel;
import com.github.microservice.auth.client.service.UserFaceService;
import com.github.microservice.components.data.base.util.PageEntityUtil;
import com.github.microservice.net.ResultContent;
import com.github.microservice.net.ResultMessage;
import com.google.common.collect.Lists;
import com.zhongshu.card.client.model.base.IDsParam;
import com.zhongshu.card.client.model.base.OutNumberModel;
import com.zhongshu.card.client.model.org.orgUser.OrganizationUserSearch;
import com.zhongshu.card.client.model.projectAbout.orgFace.*;
import com.zhongshu.card.client.model.projectAbout.projectCommon.ProjectCommonConfigModel;
import com.zhongshu.card.client.type.common.AuditState;
import com.zhongshu.card.client.type.user.OrgUserState;
import com.zhongshu.card.server.core.dao.org.UserCountDao;
import com.zhongshu.card.server.core.dao.projectAbout.OrgUserFaceDao;
import com.zhongshu.card.server.core.domain.org.OrganizationUser;
import com.zhongshu.card.server.core.domain.org.UserAccount;
import com.zhongshu.card.server.core.domain.projectAbout.OrgUserFace;
import com.zhongshu.card.server.core.service.base.CommonService;
import com.zhongshu.card.server.core.service.base.SuperService;
import com.zhongshu.card.server.core.service.devices.permiss.DevicePermissEventService;
import com.zhongshu.card.server.core.service.org.OrganizationUserServiceImpl;
import com.zhongshu.card.server.core.service.user.UserAccountServiceImpl;
import com.zhongshu.card.server.core.util.BeanUtils;
import com.zhongshu.card.server.core.util.CommonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 项目人脸管理
 *
 * @author TRX
 * @date 2024/10/12
 */
@Slf4j
@Service
public class OrgUserFaceService extends SuperService {

    @Autowired
    private OrgUserFaceDao orgUserFaceDao;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private DevicePermissEventService devicePermissEventService;

    @Autowired
    private UserCountDao userCountDao;

    /**
     * 人脸管理类
     */
    @Autowired
    private UserFaceService userFaceService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private ProjectCommonConfigService projectCommonConfigService;

    @Autowired
    private OrganizationUserServiceImpl organizationUserServiceImpl;

    @Autowired
    private UserAccountServiceImpl userAccountService;

    /**
     * 保存用户人脸信息
     *
     * @param param
     * @return
     */
    public ResultContent<OrgUserFaceModel> saveFace(OrgUserFaceParam param) {
        // 编辑 先删除
        if (StringUtils.isNotEmpty(param.getId())) {
            ResultContent resultContent = deleteFace(param.getId(), false);
            if (resultContent.isFailed()) {
                return ResultContent.buildFail(resultContent.getMsg());
            }
            param.setId(null);
        }

        String projectOid = param.getProjectOid();
        if (StringUtils.isEmpty(projectOid)) {
            projectOid = getCurrentProjectOid();
        }
        if (StringUtils.isEmpty(projectOid)) {
            return ResultContent.buildFail("oid不能为空");
        }
        String userId = "";
        if (param.getIsManager() != null && param.getIsManager()) {
            userId = param.getUserId();
        } else {
            userId = getCurrentUserId();
        }
        if (StringUtils.isEmpty(userId)) {
            return ResultContent.buildFail("用户信息为空");
        }

        String img = param.getImg();
        // 判断人脸可信度
        ResultContent<ProjectCommonConfigModel> configContent = conformFace(img, projectOid);
        if (configContent.isFailed()) {
            return ResultContent.buildFail(configContent.getMsg());
        }
        ProjectCommonConfigModel configModel = configContent.getContent();
        // 是否允许管理人脸信息
        Boolean isAllowUpdateFace = configModel.getIsAllowUpdateFace();
        if (isAllowUpdateFace == null || !isAllowUpdateFace) {
            return ResultContent.buildFail("系统不允许管理人脸信息");
        }
        // 人脸是否需要审核
        Boolean isExamineFace = configModel.getIsExamineFace();

        // 是否需要审核
        boolean isMustAudit = false;
        if ((param.getIsManager() == null || !param.getIsManager()) && isExamineFace != null && isExamineFace) {
            isMustAudit = true;
        }

        int maxFaceNumber = configModel.getMaxFaceNumber();
        int number = orgUserFaceDao.countByUserIdAndProjectOid(userId, projectOid);
        if (StringUtils.isNotEmpty(param.getId())) {
            number = number - 1;
        }
        if (number >= maxFaceNumber) {
            return ResultContent.buildFail(String.format("用户人脸数量已达上限：%d张", number));
        }

        // 所属用户userId
        UserAccount userAccount = userCountDao.findTopByUserId(userId);
        OrganizationUser organizationUser = organizationUserServiceImpl.getUserTopInProjectBindOrgUserInfo(projectOid, userAccount);
        if (organizationUser == null) {
            return ResultContent.buildFail("用户未加入项目");
        }

        String updateFaceFileId = "";
        OrgUserFace orgUserFace = null;
        if (StringUtils.isNotEmpty(param.getId())) {
            orgUserFace = orgUserFaceDao.findTopById(param.getId());
            if (ObjectUtils.isEmpty(orgUserFace)) {
                return ResultContent.buildFail(String.format(ResultMessage.DATA_NOT_EXIST, param.getId()));
            }
            initUpdateEntity(orgUserFace);
            updateFaceFileId = orgUserFace.getUpdateFaceFileId();
        } else {
            orgUserFace = new OrgUserFace();
            initEntityNoCheckOid(orgUserFace);
        }
        BeanUtils.copyProperties(param, orgUserFace, "id");

        orgUserFace.setProjectOid(projectOid);
        orgUserFace.setUpdateFaceFileId(updateFaceFileId);
        orgUserFace.setUserId(userId);
        fillEntityUserInfo(orgUserFace, organizationUser);

        if (isMustAudit) {
            // 需要审核
            orgUserFace.setIsCanUsed(Boolean.FALSE);
            orgUserFace.setAuditState(AuditState.WaitAudit);
        } else {
            // 不需要审核
            ResultContent<String> resultContent = syncFace(orgUserFace);
            if (resultContent.isFailed()) {
                return ResultContent.buildFail(resultContent.getMsg());
            }
            updateFaceFileId = resultContent.getContent();
            orgUserFace.setUpdateFaceFileId(updateFaceFileId);
            orgUserFace.setIsCanUsed(Boolean.TRUE);
            orgUserFace.setAuditState(AuditState.Audited);
            orgUserFace.setAuditUserId(getCurrentUserId());
            orgUserFace.setAuditRemark("自动通过");
            orgUserFace.setAuditTime(System.currentTimeMillis());
        }
        orgUserFace.setConfidence(configModel.getConfidence());
        orgUserFaceDao.save(orgUserFace);
        faceChange(orgUserFace);
        return ResultContent.buildSuccess(toModel(orgUserFace));
    }

    /**
     * 用户人脸信息发生变化， 下发权限
     * @param orgUserFace
     */
    private void faceChange(OrgUserFace orgUserFace) {
        if (ObjectUtils.isEmpty(orgUserFace)) {
            return;
        }
        devicePermissEventService.sendUserInfoChangeEvent(List.of(orgUserFace.getUserId()), orgUserFace.getProjectOid(), "saveFace");
    }

    /**
     * 删除多个
     *
     * @param param
     * @return
     */
    public ResultContent deleteFace(IDsParam param) {
        if (ObjectUtils.isEmpty(param.getIds())) {
            return ResultContent.buildFail("ids 不能为空");
        }
        OutNumberModel model = new OutNumberModel();
        for (String id : param.getIds()) {
            ResultContent _temp = deleteFace(id, true);
            if (_temp.isSuccess()) {
                model.addSuccess(id);
            } else {
                model.addFail(id, _temp.getMsg());
            }
        }
        return ResultContent.buildSuccess();
    }

    public ResultContent deleteFace(String id, boolean isManager) {
        OrgUserFace orgUserFace = orgUserFaceDao.findTopById(id);
        if (orgUserFace == null) {
            return ResultContent.buildFail(String.format(ResultMessage.DATA_NOT_EXIST, id));
        }
        if (!isManager) {
            // 不是管理员，需要验证是否可以删除
            ResultContent<ProjectCommonConfigModel> content = projectCommonConfigService.getConfigInfoAndCheck(orgUserFace.getProjectOid());
            if (content.isFailed()) {
                return ResultContent.buildFail(content.getMsg());
            }
            ProjectCommonConfigModel configModel = content.getContent();
            Boolean isAllowUpdateFace = configModel.getIsAllowUpdateFace();
            if (isAllowUpdateFace == null || !isAllowUpdateFace) {
                return ResultContent.buildFail("系统不允许删除人脸信息");
            }
        }
        if (StringUtils.isNotEmpty(orgUserFace.getUpdateFaceFileId())) {
            com.github.microservice.auth.client.content.ResultContent resultContent = userFaceService.delete(orgUserFace.getUserId(), orgUserFace.getUpdateFaceFileId());
            if (resultContent.isFailed()) {
                return ResultContent.buildFail(resultContent.getMsg());
            }
        }
        orgUserFaceDao.delete(orgUserFace);
        faceChange(orgUserFace);
        return ResultContent.buildSuccess();
    }

    public ResultContent<Page<OrgUserFaceModel>> page(OrgUserFaceSearch param, Pageable pageable) {

        Page<OrgUserFace> page = null;
        boolean isSearch = true;
        // 先筛选用户
        OrganizationUserSearch search = param;
        if (search.hasSearchFilter()) {
            search.setIsSearchProject(Boolean.TRUE);
            search.setAddType(null);
            search.setOrgUserState(OrgUserState.Formal);
            Pageable pageable1 = PageRequest.of(0, 1000);

            List<OrganizationUser> list = userAccountService.projectUserList(param, pageable1);
            if (ObjectUtils.isEmpty(list)) {
                page = CommonUtil.buildEmptyPage(pageable, OrgUserFace.class);
                isSearch = false;
            } else {
                param.setUserIds(list.stream().map(it -> it.getUserId()).collect(Collectors.toList()));
            }
        }
        if (isSearch) {
            page = orgUserFaceDao.page(pageable, param);
        }
        return ResultContent.buildSuccess(PageEntityUtil.concurrent2PageModel(page, this::toModel));
    }

    public ResultContent getDetail(String id) {
        OrgUserFace orgUserFace = orgUserFaceDao.findTopById(id);
        if (orgUserFace == null) {
            return ResultContent.buildFail(String.format(ResultMessage.DATA_NOT_EXIST, id));
        }
        return ResultContent.buildSuccess(toModel(orgUserFace));
    }

    /**
     * 审核批量
     *
     * @param param
     * @return
     */
    public ResultContent auditsFace(OrgUserFaceAuditsParam param) {
        List<String> ids = param.getIds();
        if (ObjectUtils.isEmpty(ids)) {
            return ResultContent.buildFail("ids不能为空");
        }
        String auditRemark = param.getAuditRemark();
        AuditState auditState = param.getAuditState();
        if (auditState == null) {
            return ResultContent.buildFail("审核状态不能为空");
        }
        if (auditState == AuditState.Refuse && StringUtils.isEmpty(auditRemark)) {
            return ResultContent.buildFail("原因不能为空");
        }

        // 操作结果
        OutNumberModel numberModel = new OutNumberModel();
        for (String id : ids) {
            OrgUserFaceAuditParam param1 = new OrgUserFaceAuditParam();
            param1.setId(id);
            param1.setAuditRemark(auditRemark);
            param1.setAuditState(auditState);
            ResultContent _temp = auditFace(param1);
            if (_temp.isSuccess()) {
                numberModel.addSuccess(id, "成功");
            } else {
                numberModel.addFail(id, _temp.getMsg());
            }
        }
        return ResultContent.buildSuccess(numberModel);
    }

    /**
     * 审核
     *
     * @param param
     * @return
     */
    public ResultContent auditFace(OrgUserFaceAuditParam param) {
        OrgUserFace orgUserFace = orgUserFaceDao.findTopById(param.getId());
        if (orgUserFace == null) {
            return ResultContent.buildFail(String.format(ResultMessage.DATA_NOT_EXIST, param.getId()));
        }
        if (orgUserFace.getAuditState() != AuditState.WaitAudit) {
            return ResultContent.buildFail("数据已审核");
        }
        BeanUtils.copyProperties(param, orgUserFace, "id");

        if (orgUserFace.getAuditState() == AuditState.Audited) {
            // 通过
            ResultContent<String> content = syncFace(orgUserFace);
            if (content.isFailed()) {
                return ResultContent.buildFail(content.getMsg());
            }
            String updateFaceFileId = content.getContent();
            orgUserFace.setUpdateFaceFileId(updateFaceFileId);
            orgUserFace.setIsCanUsed(Boolean.TRUE);
        } else {
            orgUserFace.setIsCanUsed(Boolean.FALSE);
        }
        orgUserFace.setAuditUserId(getCurrentUserId());
        orgUserFace.setAuditTime(System.currentTimeMillis());
        orgUserFaceDao.save(orgUserFace);
        faceChange(orgUserFace);
        return ResultContent.buildSuccess();
    }

    /**
     * 同步人脸信息
     *
     * @param orgUserFace
     * @return
     */
    private ResultContent<String> syncFace(OrgUserFace orgUserFace) {
        String updateFaceFileId = orgUserFace.getUpdateFaceFileId();
        String userId = orgUserFace.getUserId();
        String faceBase64 = commonService.getUrlFileBase64(orgUserFace.getImg());
        // 维护管理权限中心用户的头像信息
        UserFaceUploadModel userFaceUploadModel = new UserFaceUploadModel();
        userFaceUploadModel.setUserId(userId);
        userFaceUploadModel.setFile(faceBase64);
        userFaceUploadModel.setUpdateFaceFileId(updateFaceFileId);
        com.github.microservice.auth.client.content.ResultContent<String> content = userFaceService.upload(userFaceUploadModel);
        if (content.isFailed()) {
            return ResultContent.buildFail(content.getMsg());
        }
        updateFaceFileId = content.getContent();
//        String groupId = CommonUtil.UUID();
//        Map<String, Object> map = new HashMap<>();
//        map.put("groupId", groupId);
//        // 通知人脸信息发送变化
//        devicePermissEventService.sendUserInfoChangeEvent(orgUserFace.getUserId(), orgUserFace.getProjectOid(), map);
        return ResultContent.buildSuccess(updateFaceFileId);
    }

    public OrgUserFace getUserFace(String userId, String oid) {
        if (StringUtils.isNotEmpty(userId) && StringUtils.isNotEmpty(oid)) {
            return orgUserFaceDao.findTopByUserIdAndProjectOidOrderByCreateTimeDesc(userId, oid);
        }
        return null;
    }

    public ResultContent<List<OrgUserFaceSimpleModel>> getCurrentUserAllFace(String projectOid) {
        String userId = getCurrentUserId();
        if (StringUtils.isEmpty(projectOid)) {
            projectOid = getCurrentProjectOid();
        }
        if (StringUtils.isEmpty(projectOid)) {
            return ResultContent.buildFail("项目oid不能为空");
        }
        return getUserAllFace(userId, projectOid);
    }

    public ResultContent<List<OrgUserFaceSimpleModel>> getUserAllFace(String userId, String projectOid) {
        List<OrgUserFace> list = orgUserFaceDao.findByUserIdAndProjectOidOrderByCreateTimeDesc(userId, projectOid);
        List<OrgUserFaceSimpleModel> models = new ArrayList<>();
        if (ObjectUtils.isNotEmpty(list)) {
            models = list.stream().map(this::toSimpleModel).collect(Collectors.toList());
        }
        return ResultContent.buildSuccess(models);
    }

    public ResultContent<List<OrgUserFaceSimpleModel>> getUserAllFacePass(String userId, String projectOid) {
        List<OrgUserFace> list = orgUserFaceDao.findByProjectOidAndUserIdInAndAuditState(
                projectOid, List.of(userId), AuditState.Audited);
        List<OrgUserFaceSimpleModel> models = new ArrayList<>();
        if (ObjectUtils.isNotEmpty(list)) {
            models = list.stream().map(this::toSimpleModel).collect(Collectors.toList());
        }
        return ResultContent.buildSuccess(models);
    }

    /**
     * 得到用户的人脸信息
     *
     * @param projectOid
     * @param userIds
     * @return
     */
    public List<OrgUserFace> getUserFaces(String projectOid, List<String> userIds) {
        if (ObjectUtils.isNotEmpty(userIds) && StringUtils.isNotEmpty(projectOid)) {
            return orgUserFaceDao.findByProjectOidAndUserIdInAndAuditState(projectOid, userIds, AuditState.Audited);
        }
        return Lists.newArrayList();
    }

    /**
     * 判断人脸可信度
     *
     * @param url
     * @param projectOid
     * @return
     */
    public ResultContent<ProjectCommonConfigModel> conformFace(String url, String projectOid) {
        if (StringUtils.isEmpty(projectOid)) {
            projectOid = getCurrentProjectOid();
        }
        if (StringUtils.isEmpty(projectOid)) {
            return ResultContent.buildFail("项目oid信息为空");
        }
        ResultContent<ProjectCommonConfigModel> content = projectCommonConfigService.getConfigInfoAndCheck(projectOid);
        if (content.isFailed()) {
            return ResultContent.buildFail(content.getMsg());
        }
        return conformFace(url, content.getContent());
    }

    /**
     * 判断人脸识别度是否符合要求
     *
     * @param url
     * @param configModel
     * @return
     */
    public ResultContent<ProjectCommonConfigModel> conformFace(String url, ProjectCommonConfigModel configModel) {
        if (StringUtils.isEmpty(url)) {
            return ResultContent.buildFail("图片为空");
        }
        if (ObjectUtils.isEmpty(configModel) || configModel.getSimilarity() == null) {
            return ResultContent.buildSuccess();
        }
        String imageBase64 = commonService.getUrlFileBase64(url);
        UserFaceConfidenceModel faceConfidenceModel = new UserFaceConfidenceModel();
        faceConfidenceModel.setFile(imageBase64);
        com.github.microservice.auth.client.content.ResultContent<Double> content = userFaceService.confidence(faceConfidenceModel);
        if (content.isFailed()) {
            return ResultContent.buildFail(content.getMsg());
        }
        Double confidence = content.getContent() * 100;
        if (BigDecimal.valueOf(confidence).compareTo(BigDecimal.valueOf(configModel.getSimilarity())) >= 0) {
            configModel.setConfidence(BigDecimal.valueOf(confidence));
            return ResultContent.buildSuccess(configModel);
        } else {
            return ResultContent.buildFail(String.format("未检测到人脸: %d", confidence.intValue()));
        }
    }

    /**
     * 项目用户信息发生变化，更新人脸信息冗余的用户信息
     *
     * @param organizationUser
     */
    public void updateAllUser(OrganizationUser organizationUser) {
        if (ObjectUtils.isNotEmpty(organizationUser)) {
            List<OrgUserFace> list = orgUserFaceDao.findByUserIdAndProjectOidOrderByCreateTimeDesc(organizationUser.getUserId(), organizationUser.getProjectOid());
            if (ObjectUtils.isNotEmpty(list)) {
                for (OrgUserFace orgUserFace : list) {
                    fillEntityUserInfo(orgUserFace, organizationUser);
                    orgUserFaceDao.save(orgUserFace);
                }
            }
        }
    }


    /**
     * 填充用户信息
     *
     * @param entity
     * @param organizationUser
     */
    public void fillEntityUserInfo(OrgUserFace entity, OrganizationUser organizationUser) {
        if (ObjectUtils.isNotEmpty(entity)) {
            entity.setOrganizationUser(organizationUser);
            if (ObjectUtils.isNotEmpty(organizationUser)) {
                if (organizationUser.getOrganization() != null) {
                    entity.setUserOrgOid(organizationUser.getOrganization().getOid());
                }
                entity.setDepartment(organizationUser.getDepartment());
                entity.setRoleIds(organizationUser.getRoleIds());
                entity.setPosition(organizationUser.getPosition());
                entity.setCode(organizationUser.getCode());
            }
            UserAccount userAccount = organizationUser.getUser();
            if (ObjectUtils.isNotEmpty(userAccount)) {
                if (ObjectUtils.isNotEmpty(userAccount)) {
                    entity.setUserAccount(userAccount);
                    entity.setUserName(userAccount.getName());
                    entity.setPhone(userAccount.getPhone());
                    entity.setSex(userAccount.getSex());
                }
            }
        }
    }

    public OrgUserFaceModel toModel(OrgUserFace entity) {
        OrgUserFaceModel model = null;
        if (ObjectUtils.isNotEmpty(entity)) {
            model = new OrgUserFaceModel();
            BeanUtils.copyProperties(entity, model);
            model.setUserAccount(userAccountService.toSimpleDesenModel(entity.getUserAccount()));
            model.setOrganizationUser(organizationUserServiceImpl.toModel(entity.getOrganizationUser()));
            model.setAuditUserAccount(userAccountService.toSimpleModel(entity.getAuditUserId()));
        }
        return model;
    }

    public OrgUserFaceSimpleModel toSimpleModel(OrgUserFace entity) {
        OrgUserFaceSimpleModel model = null;
        if (ObjectUtils.isNotEmpty(entity)) {
            model = new OrgUserFaceSimpleModel();
            BeanUtils.copyProperties(entity, model);
            model.setUserAccount(userAccountService.toSimpleDesenModel(entity.getUserAccount()));
        }
        return model;
    }

}
