package com.bonus.core.customer.v4.mobile.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.redis.service.RedisService;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.core.account.v3.constants.AccStatusEnum;
import com.bonus.core.allocation.api.GlobalMetadataApi;
import com.bonus.core.allocation.mobile.dto.MobileMetadataDTO;
import com.bonus.core.common.enums.MetadataModelTypeEnum;
import com.bonus.oss.OssProperties;
import com.bonus.oss.service.OssTemplate;
import com.bonus.core.common.utils.SysUtil;
import com.bonus.core.customer.business.CustPhotoPointBusiness;
import com.bonus.core.customer.constants.FeaturesBuildStatusEnum;
import com.bonus.core.customer.constants.PhotoTypeEnum;
import com.bonus.core.customer.dto.UnifiedFaceRegisterParamDTO;
import com.bonus.core.customer.dto.UploadPhotoGenCodeDTO;
import com.bonus.core.customer.mapper.CustPhotoMapper;
import com.bonus.core.customer.model.CustAccTemp;
import com.bonus.core.customer.model.CustPhoto;
import com.bonus.core.customer.mq.DelayedMessageSender;
import com.bonus.core.customer.mq.DelayedMessageTypeEnum;
import com.bonus.core.customer.service.CustAccTempService;
import com.bonus.core.customer.service.CustInfoService;
import com.bonus.core.customer.service.FaceRegisterService;
import com.bonus.core.customer.utils.CustomerUtil;
import com.bonus.core.customer.v4.mobile.service.CustPhotoService;
import com.bonus.core.customer.vo.MultiModelFaceVO;
import com.bonus.core.device.door.api.DcPushUserDataServiceApi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import cn.hutool.core.codec.Base64;

import javax.annotation.Resource;


@Service
public class CustPhotoServiceImpl extends ServiceImpl<CustPhotoMapper, CustPhoto> implements CustPhotoService {
    private static final Logger log = LoggerFactory.getLogger(CustPhotoServiceImpl.class);
    @Resource
    @Lazy
    private GlobalMetadataApi globalMetadataApi;
    @Resource
    private FaceRegisterService faceRegisterService;
    @Resource
    private OssTemplate ossTemplate;
    @Resource
    private OssProperties ossProperties;
    @Resource
    @Lazy
    private CustPhotoPointBusiness custPhotoPointBusiness;
    @Resource
    @Lazy
    private CustInfoService custInfoService;
    @Resource
    @Lazy
    private CustAccTempService custAccTempService;
    @Lazy
    @Resource
    private DelayedMessageSender delayedMessageSender;
    @Resource
    private RedisService redisService;
    @Resource
    DcPushUserDataServiceApi dcPushUserDataServiceApi;

    @Value("${system.sysfile.max-upload-file-size}")
    private Double maxFileSize;

    @Override
    @Transactional(
            rollbackFor = {Exception.class}
    )
    public AjaxResult appletRegisterAndSaveFaceInfo(UploadPhotoGenCodeDTO appletSaveFaceDTO) {
        LocalDate expireDate = CustomerUtil.getExpireDate(appletSaveFaceDTO.getExpirDay());
        return this.registerAndSaveFaceInfo(appletSaveFaceDTO.getCustId(), appletSaveFaceDTO.getPhotoUrl(), expireDate, false);
    }

    public AjaxResult registerAndSaveFaceInfo(Long custId, String cutPhotoUrl, LocalDate expireDate, boolean isSaveErrorPicture) {
        MobileMetadataDTO mobileDTO = (MobileMetadataDTO) this.globalMetadataApi.getModel(MetadataModelTypeEnum.MOBILE, new MobileMetadataDTO(), (Long) null, (Long) null);
        String ifAllowBackUploadPhoto = mobileDTO.getIfAllowBackUploadPhoto();
        if ("1".equals(ifAllowBackUploadPhoto) && Boolean.TRUE.equals(isSaveErrorPicture)) {
            throw new ServiceException("不允许后台上传照片!!!");
        } else {
            cutPhotoUrl = SysUtil.getCutPath(cutPhotoUrl);
            log.info("照片url截取后路径:{}", cutPhotoUrl);
            String photoName = getUnBucketNamePrefixPath(cutPhotoUrl);
            log.info("路径截取存储桶前缀后:{}", photoName);

            String imageBse64;
            try {
                InputStream in = this.ossTemplate.getObject(this.ossProperties.getBucketName(), photoName);

                try {
                    imageBse64 = Base64.encode(in);
                    this.checkUploadFileSize(imageBse64);
                } catch (Throwable var14) {
                    if (in != null) {
                        try {
                            in.close();
                        } catch (Throwable var13) {
                            var14.addSuppressed(var13);
                        }
                    }

                    throw var14;
                }

                if (in != null) {
                    in.close();
                }
            } catch (IOException var15) {
                log.error("照片获取失败:{}", var15.getMessage(), var15);
                return AjaxResult.error("照片获取失败");
            }

            UnifiedFaceRegisterParamDTO paramDTO = UnifiedFaceRegisterParamDTO.builder().custId(custId).minioPicPath(cutPhotoUrl).imageBase64(imageBse64).build();
            List<MultiModelFaceVO> modelVOList = this.faceRegisterService.multiModelRegisterHandler(paramDTO, isSaveErrorPicture);
            this.saveMultiModelFacePhoto(custId, cutPhotoUrl, expireDate, modelVOList);
            this.custPhotoPointBusiness.addRegisterPhotoPoint(custId, cutPhotoUrl, isSaveErrorPicture, modelVOList);
            List<MultiModelFaceVO> collect = (List) modelVOList.stream().filter((e) -> {
                return Boolean.FALSE.equals(e.getSuccess());
            }).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(collect)) {
                throw new ServiceException("[旷世算法]:未成功注册人脸模型");
            } else {
                return AjaxResult.success();
            }
        }
    }

    protected static String getUnBucketNamePrefixPath(String url) {
        url = url.substring(url.indexOf("/", url.indexOf("/") + 1) + 1);
        if (CharSequenceUtil.isNotBlank(url) && url.contains("?")) {
            url = url.substring(0, url.indexOf("?"));
        }

        return url;
    }

    protected void checkUploadFileSize(String base64File) {
        if (!ObjectUtil.isEmpty(base64File)) {
            byte[] decodedBytes = Base64.decode(base64File);
            long fileSizeInBytes = (long) decodedBytes.length;
            if ((double) fileSizeInBytes > this.maxFileSize * 1024.0 * 1024.0) {
                throw new ServiceException("上传文件大小超过限制");
            }
        }
    }

    public AjaxResult saveMultiModelFacePhoto(Long custId, String path, LocalDate expireDate,
                                              List<MultiModelFaceVO> modelVOList) {
        String cutPath = SysUtil.getCutPath(path);
        List<CustPhoto> originalFile = this.getByCustId(custId);
        Iterator var7 = modelVOList.iterator();

        while (var7.hasNext()) {
            MultiModelFaceVO faceVO = (MultiModelFaceVO) var7.next();
            this.insertOrUpdateCustPhoto(faceVO, custId, cutPath, expireDate);
        }

        if (CollUtil.isNotEmpty(originalFile)) {
            List<String> originalFiles = (List) originalFile.stream().map(CustPhoto::getPhotoUrl).filter(CharSequenceUtil::isNotEmpty).distinct().collect(Collectors.toList());
            Iterator var13 = originalFiles.iterator();

            while (var13.hasNext()) {
                String fileName = (String) var13.next();

                try {
                    if (!Objects.equals(fileName, cutPath)) {
                        this.ossTemplate.removeObject(this.ossProperties.getBucketName(), getUnBucketNamePrefixPath(fileName));
                    }
                } catch (Exception var11) {
                    log.error("[原照片minio]删除异常:{}", var11.getMessage(), var11);
                }
            }
        }

        this.custInfoService.updateCustPhotoUrl(custId, cutPath);
       this.custAccTempService.update(
               new CustAccTemp().setCustId(custId).setCustPhotoUrl(cutPath).setUpby(SecurityUtils.getLoginUser().getSysUser().getPhonenumber()),
               new LambdaQueryWrapper<CustAccTemp>().eq(CustAccTemp::getCustId, custId)
               );
        this.delayedMessageSender.asyncDelaySendToDevice(DelayedMessageTypeEnum.PHOTO);
        this.delayedMessageSender.asyncDelaySendToDevice(DelayedMessageTypeEnum.EXPIRED);
        this.dcPushUserDataServiceApi.editUser(custId);
        return AjaxResult.success();
    }

    protected List<CustPhoto> getByCustId(Long custId) {
        return ((CustPhotoMapper) this.baseMapper).selectList(new LambdaQueryWrapper<CustPhoto>().eq(CustPhoto::getCustId, custId));
    }

    public void insertOrUpdateCustPhoto(MultiModelFaceVO faceVO, Long custId, String cutPath, LocalDate expireDate) {
        CustPhoto custPhoto = this.getCustPhotoByCustId(custId, faceVO.getFaceVer());
        custPhoto.setPhotoUrl(cutPath);
        custPhoto.setErrorMsg(faceVO.getMsg());
        custPhoto.setFeatures(faceVO.getFeature());
        custPhoto.setFaceVer(faceVO.getFaceVer());
        custPhoto.setPhotoState(AccStatusEnum.NORMAL.getKey());
        custPhoto.setCustId(custId);
        custPhoto.setPhotoType(PhotoTypeEnum.PHOTO.getKey());
        custPhoto.setExpireDate(expireDate);
        if (Boolean.TRUE.equals(faceVO.getSuccess())) {
            custPhoto.setFeaturesBuildStatus(FeaturesBuildStatusEnum.CREATE_SUCC.getKey());
            custPhoto.setFeaturesBuildTime(LocalDateTime.now());
        } else {
            custPhoto.setFeaturesBuildStatus(FeaturesBuildStatusEnum.CREATE_FAIL.getKey());
        }

        custPhoto.setUptime(LocalDateTime.now());
        this.saveOrUpdate(custPhoto);
    }

    protected CustPhoto getCustPhotoByCustId(Long custId, Integer faceVer) {
        CustPhoto custPhoto = ((CustPhotoMapper) this.baseMapper).selectOne(new LambdaQueryWrapper<CustPhoto>()
                        .eq(CustPhoto::getFaceVer, faceVer)
                        .eq(CustPhoto::getCustId, custId));
        return (CustPhoto) Optional.ofNullable(custPhoto).orElse(new CustPhoto());
    }
}
