package com.ktg.system.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ktg.common.config.RuoYiConfig;
import com.ktg.common.core.domain.entity.SysUser;
import com.ktg.common.utils.FileDriveLetterUtils;
import com.ktg.common.utils.StringUtils;
import com.ktg.common.utils.face.ArcSoftMothodUtil;
import com.ktg.common.utils.face.FaceCutUtil;
import com.ktg.common.vo.FaceCutVO;
import com.ktg.system.domain.SysUserCharacteristic;
import com.ktg.system.mapper.SysUserCharacteristicMapper;
import com.ktg.system.service.ISysUserCharacteristicService;
import com.ktg.system.service.ISysUserService;
import com.machinezoo.sourceafis.FingerprintMatcher;
import com.machinezoo.sourceafis.FingerprintTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;

/**
 * 用户特征(指纹、面部)Service业务层处理
 *
 * @author cgj
 * @date 2025-03-10
 */
@Service
public class SysUserCharacteristicServiceImpl extends ServiceImpl<SysUserCharacteristicMapper, SysUserCharacteristic> implements ISysUserCharacteristicService {

    @Autowired
    private SysUserCharacteristicMapper sysUserCharacteristicMapper;
    @Value("${ktg-mes.prod}")
    private String prodApi;
    @Value("${server.port}")
    private String port;
    @Autowired
    private ISysUserService iSysUserService;
    private static final double THRESHOLD = 40; // 相当于错误率是0.01%，THRESHOLD越高，错误率越低

    @Override
    public Page<SysUserCharacteristic> getSysUserCharacteristicPage(Page<SysUserCharacteristic> page, SysUserCharacteristic sysUserCharacteristic) {
        Page<SysUserCharacteristic> result = page(page, Wrappers.<SysUserCharacteristic>lambdaQuery()
                .eq(sysUserCharacteristic.getUserId() != null, SysUserCharacteristic::getUserId, sysUserCharacteristic.getUserId())
                .eq(StringUtils.isNotBlank(sysUserCharacteristic.getType()), SysUserCharacteristic::getType, sysUserCharacteristic.getType())
                .eq(StringUtils.isNotBlank(sysUserCharacteristic.getGroupCode()), SysUserCharacteristic::getGroupCode, sysUserCharacteristic.getGroupCode())
                .orderByDesc(SysUserCharacteristic::getRecordId));
        return result;
    }

    @Override
    public Long insertUserFingerprintDat(MultipartFile file, String userName, String sysAttrValue, String url, String group) throws IOException {
        Assert.notBlank(userName, "请告知我这是哪个用户的指纹！");
        Assert.notBlank(group, "指纹分组不可为空！");
        Assert.isTrue(file.getSize() > 0, "指纹信息不能为空！");
        SysUser user = iSysUserService.getOne(Wrappers.<SysUser>lambdaQuery()
                .eq(SysUser::getUserName, userName));
        Assert.isFalse(user == null, "系统中无该用户！");
        Long userId = user.getUserId();
        if (StringUtils.isNotBlank(sysAttrValue)) {
            // 检查人员指纹上限
            long count = count(Wrappers.<SysUserCharacteristic>lambdaQuery()
                    .eq(SysUserCharacteristic::getType, "1")
                    .eq(SysUserCharacteristic::getUserId, userId));
            int i = Integer.parseInt(sysAttrValue);
            Assert.isFalse(count >= i, "该人员的指纹录入已上限，最大" + i + "条！");
        }
        // 时间戳
        long currentTimestamp = System.currentTimeMillis();
        // 设置文件路径
        String filePath = FileDriveLetterUtils.getDriveLetter() + RuoYiConfig.getProfile() + "/finger/" + userId + "/";
        // 确保目录存在
        Path uploadPath = Paths.get(filePath);
        if (!Files.exists(uploadPath)) {
            Files.createDirectories(uploadPath);
        }

        // 获取文件名并构建目标路径
        String fileName = userId + "_" + currentTimestamp + file.getOriginalFilename();
        Path targetLocation = uploadPath.resolve(fileName);
        // 将文件写入目标路径
        file.transferTo(targetLocation.toFile());

        // 开始生成dat文件
        String imagePath = null;
        String imageUrl = null;
        Path path = null;
        try {
            imagePath = filePath + fileName; // 替换为你的指纹图片路径
            byte[] fingerprintData = extractFingerprintTemplate(imagePath);

            // 保存到文件
            path = Paths.get(filePath + userId + "_" + currentTimestamp + ".dat");
            Files.write(path, fingerprintData);
            System.out.println("指纹特征值已保存！");
            // 图片地址
            String profile = RuoYiConfig.getProfile();   // /home/iscs
            if (StringUtils.isBlank(prodApi)) {
                // 本地win
                imageUrl = imagePath.replace(FileDriveLetterUtils.getDriveLetter() + profile, url + "/profile");
            } else  {
                // 服务器linux / win
                if (url.contains(port)) {
                    // 说明是后端上传
                    imageUrl = imagePath.replace(FileDriveLetterUtils.getDriveLetter() + profile, url + "/profile");
                } else {
                    imageUrl = imagePath.replace(FileDriveLetterUtils.getDriveLetter() + profile, url + "/prod-api" + "/profile");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            // 删除指纹图片
            deleteFileByPath(imagePath);
            Assert.isFalse(true, "该文件指纹无法识别，请重新录入！");
        }
        // 查询该人员的分组有没有指纹
        List<SysUserCharacteristic> list = list(Wrappers.<SysUserCharacteristic>lambdaQuery()
                .eq(SysUserCharacteristic::getUserId, userId)
                .eq(SysUserCharacteristic::getGroupCode, group));
        if (!list.isEmpty()) {
            FingerprintTemplate fingerprintTemplate = new FingerprintTemplate().deserialize(new String(Files.readAllBytes(path)));
            // 输入的被验证指纹
            FingerprintMatcher matcher = new FingerprintMatcher(fingerprintTemplate);
            for (SysUserCharacteristic sysUserCharacteristic : list) {
                // 输入的指纹和指纹库中的指纹进行对比，找到当前线程中的分数最高的指纹
                FingerprintTemplate matcherTemp = new FingerprintTemplate().deserialize(new String(Files.readAllBytes(Paths.get(sysUserCharacteristic.getContent()))));
                double score = matcher.match(matcherTemp);
                if (score < THRESHOLD) {
                    deleteFileByPath(imagePath);
                    deleteFileByPath(filePath + userId + "_" + currentTimestamp + ".dat");
                    Assert.isTrue(false, "指纹相似度相差较大，请重新录入！");
                }
            }
        }
        SysUserCharacteristic sysUserCharacteristic = new SysUserCharacteristic();
        sysUserCharacteristic.setUserId(userId);
        sysUserCharacteristic.setGroupCode(group);
        sysUserCharacteristic.setType("1");
        sysUserCharacteristic.setContent(filePath + userId + "_" + currentTimestamp + ".dat");
        sysUserCharacteristic.setOrderNum(0);
        sysUserCharacteristic.setImageUrl(imageUrl);
        sysUserCharacteristic.setImagePath(imagePath);
        save(sysUserCharacteristic);
        return sysUserCharacteristic.getRecordId();
    }

    private void deleteFileByPath(String path) {
        File file1 = new File(path);
        file1.delete();
    }

    public static byte[] extractFingerprintTemplate(String imagePath) throws IOException {
        // 读取图像文件（灰度图像 PNG, BMP, JPEG 等）
        byte[] imageBytes = Files.readAllBytes(Paths.get(imagePath));
        try {
            // 提取特征值
            FingerprintTemplate template = new FingerprintTemplate()
                    .dpi(500) // 指定 DPI (重要，通常为 500)
                    .create(imageBytes);
            // 导出为 byte[] 保存特征值
            return template.serialize().getBytes();
        } catch (Exception e) {
            Assert.isFalse(true, "该文件指纹无法识别，请重新录入！");
        }
        return null;
    }

    @Override
    public FaceCutVO insertUserCutFace(MultipartFile file, String userName, String sysAttrValue, String url) throws IOException {
        Assert.notBlank(userName, "请告知我这是哪个用户的人脸！");
        Assert.isTrue(file.getSize() > 0, "人脸信息不能为空！");
        SysUser user = iSysUserService.getOne(Wrappers.<SysUser>lambdaQuery()
                .eq(SysUser::getUserName, userName));
        Assert.isFalse(user == null, "系统中无该用户！");
        Long userId = user.getUserId();
        if (StringUtils.isNotBlank(sysAttrValue)) {
            // 检查人员人脸上限
            long count = count(Wrappers.<SysUserCharacteristic>lambdaQuery()
                    .eq(SysUserCharacteristic::getUserId, userId)
                    .eq(SysUserCharacteristic::getType, "2"));
            int i = Integer.parseInt(sysAttrValue);
            Assert.isFalse(count >= i, "该人员的人脸录入已上限，最大" + i + "条！");
        }
        FaceCutVO faceCutVO = FaceCutUtil.imageFaceDetection(file, userId, url);
        SysUserCharacteristic sysUserCharacteristic = new SysUserCharacteristic();
        sysUserCharacteristic.setUserId(userId);
        sysUserCharacteristic.setType("2");
        sysUserCharacteristic.setContent(faceCutVO.getContent());
        sysUserCharacteristic.setOrderNum(0);
        sysUserCharacteristic.setImageUrl(faceCutVO.getImageUrl());
        sysUserCharacteristic.setImagePath(faceCutVO.getImagePath());
        sysUserCharacteristic.setMatData(faceCutVO.getMatData());
        sysUserCharacteristic.setMatRows(faceCutVO.getMatRows());
        sysUserCharacteristic.setMatCols(faceCutVO.getMatCols());
        sysUserCharacteristic.setMatType(faceCutVO.getMatType());
        save(sysUserCharacteristic);
        return faceCutVO;
    }

    @Override
    public FaceCutVO insertUserFace(MultipartFile file, String userName, String sysAttrValue, String url) throws IOException {
        Assert.notBlank(userName, "请告知我这是哪个用户的人脸！");
        Assert.isTrue(file.getSize() > 0, "人脸信息不能为空！");
        SysUser user = iSysUserService.getOne(Wrappers.<SysUser>lambdaQuery()
                .eq(SysUser::getUserName, userName));
        Assert.isFalse(user == null, "系统中无该用户！");
        Long userId = user.getUserId();
        if (StringUtils.isNotBlank(sysAttrValue)) {
            // 检查人员人脸上限
            long count = count(Wrappers.<SysUserCharacteristic>lambdaQuery()
                    .eq(SysUserCharacteristic::getUserId, userId)
                    .eq(SysUserCharacteristic::getType, "2"));
            int i = Integer.parseInt(sysAttrValue);
            Assert.isFalse(count >= i, "该人员的人脸录入已上限，最大" + i + "条！");
        }
        FaceCutVO faceCutVO = ArcSoftMothodUtil.saveArcData(file, userId, url);
        SysUserCharacteristic sysUserCharacteristic = new SysUserCharacteristic();
        sysUserCharacteristic.setUserId(userId);
        sysUserCharacteristic.setType("2");
        sysUserCharacteristic.setContent(faceCutVO.getContent());
        sysUserCharacteristic.setOrderNum(0);
        sysUserCharacteristic.setImageUrl(faceCutVO.getImageUrl());
        sysUserCharacteristic.setImagePath(faceCutVO.getImagePath());
        save(sysUserCharacteristic);
        return faceCutVO;
    }

    @Override
    public Boolean deleteSysUserCharacteristicByRecordIds(String recordIds) {
        Assert.notBlank(recordIds, "请选择需要删除的数据!");
        Long[] longIds = Convert.toLongArray(recordIds);
        List<Long> list = Arrays.asList(longIds);
        List<SysUserCharacteristic> sysUserCharacteristics = listByIds(list);
        for (SysUserCharacteristic sysUserCharacteristic : sysUserCharacteristics) {
            if (StringUtils.isNotBlank(sysUserCharacteristic.getContent())) {
                try {
                    File file = new File(sysUserCharacteristic.getContent());
                    if (!file.delete()) {
                        log.error("DAT文件删除失败: " + sysUserCharacteristic.getContent());
                    }
                    File file1 = new File(sysUserCharacteristic.getImagePath());
                    if (!file1.delete()) {
                        log.error("img文件删除失败: " + sysUserCharacteristic.getImagePath());
                    }
                } catch (Exception e) {
                    log.error("存在异常文件：{}", e);
                }
            }
        }
        return removeBatchByIds(list);
    }

}
