package com.sz.admin.monitor.service.impl;


import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.sz.admin.monitor.mapper.EdgeBoxMapper;
import com.sz.admin.monitor.mapper.FaceInfoMapper;
import com.sz.admin.monitor.mapper.FaceLibraryMapper;
import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoCreateDTO;
import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoImportDTO;
import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoListDTO;
import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoUpdateDTO;
import com.sz.admin.monitor.pojo.po.EdgeBox;
import com.sz.admin.monitor.pojo.po.FaceImage;
import com.sz.admin.monitor.pojo.po.FaceInfo;
import com.sz.admin.monitor.pojo.po.FaceLibrary;
import com.sz.admin.monitor.pojo.vo.faceimage.FaceImageVO;
import com.sz.admin.monitor.pojo.vo.faceinfo.FaceInfoVO;
import com.sz.admin.monitor.pojo.vo.facelibrary.FaceLibraryVO;
import com.sz.admin.monitor.service.FaceImageService;
import com.sz.admin.monitor.service.FaceInfoService;
import com.sz.admin.monitor.utils.AiBoxRequestUtil;
import com.sz.admin.monitor.utils.UrlConvert;
import com.sz.core.common.entity.ImportExcelDTO;
import com.sz.core.common.entity.PageResult;
import com.sz.core.common.entity.SelectIdsDTO;
import com.sz.core.common.enums.CommonResponseEnum;
import com.sz.core.common.exception.common.BusinessException;
import com.sz.core.datascope.SimpleDataScopeHelper;
import com.sz.core.util.BeanCopyUtils;
import com.sz.core.util.FileUtils;
import com.sz.core.util.PageUtils;
import com.sz.core.util.Utils;
import com.sz.excel.core.ExcelResult;
import com.sz.excel.utils.ExcelUtils;
import com.sz.platform.enums.AdminResponseEnum;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.Base64;
import java.util.List;

/**
 * <p>
 * 人脸信息表 服务实现类
 * </p>
 *
 * @author Lz
 * @since 2026-02-26
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class FaceInfoServiceImpl extends ServiceImpl<FaceInfoMapper, FaceInfo> implements FaceInfoService {
    private final FaceImageService faceImageService;
    private final FaceLibraryMapper faceLibraryMapper;
    private final AiBoxRequestUtil aiBoxRequestUtil;
    private final EdgeBoxMapper edgeBoxMapper;
    @Override
    public void create(FaceInfoCreateDTO dto) {
        String imageUrl = dto.getImageUrl();
        String base64Image = null;
        try {
            String realFilePath = getRealFilePath(imageUrl);
            java.io.File file = new java.io.File(realFilePath);
            if (!file.exists()) {
                throw new BusinessException(AdminResponseEnum.OPERATION_FAIL,null, "读取人脸图片失败，文件不存在");
            }
            byte[] fileBytes = Files.readAllBytes(Paths.get(realFilePath));
            base64Image = Base64.getEncoder().encodeToString(fileBytes);
        } catch (IOException e) {
            throw new BusinessException(AdminResponseEnum.OPERATION_FAIL,null, "处理人脸图片文件时发生异常");
        }
        Long libraryId = dto.getLibraryId();
        FaceLibrary faceLibrary = faceLibraryMapper.selectOneById(libraryId);
        Long boxId = faceLibrary.getBoxId();
        EdgeBox edgeBox = edgeBoxMapper.selectOneById(boxId);
        aiBoxRequestUtil.registerFaceLibrary(edgeBox.getIp(), edgeBox.getPort(), faceLibrary.getName(),
                dto.getFaceSign(),
                dto.getName(),
                base64Image);
        try {
            this.saveFaceDataToDb(dto, imageUrl);
        } catch (Exception e) {
            log.error("本地数据库保存人脸失败，开始回滚 AI 盒子数据。人员: {}", dto.getName(), e);
            try {
                // 调用盒子端“删除人脸”的接口
                aiBoxRequestUtil.deleteFaceInfo(edgeBox.getIp(), edgeBox.getPort(), dto.getFaceSign(), faceLibrary.getName());
            } catch (Exception rollbackEx) {
                log.error("【严重告警】本地落库失败，且 AI 盒子数据回滚失败！需人工排查脏数据。", rollbackEx);
            }
            // 向前端抛出异常
            throw new BusinessException(AdminResponseEnum.OPERATION_FAIL,null, "系统内部异常，保存人脸数据失败");
        }
    }
    @Transactional(rollbackFor = Exception.class)
    public void saveFaceDataToDb(FaceInfoCreateDTO dto, String imageUrl) {
        FaceInfo ryFaceInfo = BeanCopyUtils.copy(dto, FaceInfo.class);
        ryFaceInfo.setRegisterTime(LocalDateTime.now());
        save(ryFaceInfo);
        FaceImage faceImage = new FaceImage();
        faceImage.setImageUrl(imageUrl);
        faceImage.setFaceInfoId(ryFaceInfo.getId());
        faceImage.setUploadTime(LocalDateTime.now());
        faceImageService.save(faceImage);
    }
    private String getRealFilePath(String imageUrl) {
         String basePath="D:/work/images";
         return basePath + imageUrl.replace("/save", "");
    }
    @Override
    public void update(FaceInfoUpdateDTO dto){
        FaceInfo ryFaceInfo = BeanCopyUtils.copy(dto, FaceInfo.class);
        QueryWrapper wrapper;
        // id有效性校验
        wrapper = QueryWrapper.create()
            .eq(FaceInfo::getId, dto.getId());
        CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0);
        saveOrUpdate(ryFaceInfo);
    }

    @Override
    public PageResult<FaceInfoVO> page(FaceInfoListDTO dto){
        try {
            SimpleDataScopeHelper.start(FaceInfo.class);
            Page<FaceInfoVO> page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto),  FaceInfoVO.class);
            List<FaceInfoVO> result = page.getRecords().stream().map(faceInfoVO -> {
                Long id = faceInfoVO.getId();
                Long faceLibraryId = faceInfoVO.getLibraryId();
                // 根据人脸库id查询人脸库
                FaceLibrary faceLibrary = faceLibraryMapper.selectOneById(faceLibraryId);
                // PO转VO
                faceInfoVO.setFaceLibraryVO(BeanCopyUtils.copy(faceLibrary, FaceLibraryVO.class));
                List<FaceImageVO> faceImageVOS= faceImageService.getByFaceId(id);
                faceInfoVO.setFaceImageList(faceImageVOS);
                return faceInfoVO;
            }).toList();
            page.setRecords(result);
            return PageUtils.getPageResult(page);
        } finally {
            SimpleDataScopeHelper.clearDataScope();
        }
    }

    @Override
    public List<FaceInfoVO> list(FaceInfoListDTO dto){
        try {
            SimpleDataScopeHelper.start(FaceInfo.class);
            return listAs(buildQueryWrapper(dto), FaceInfoVO.class);
        } finally {
            SimpleDataScopeHelper.clearDataScope();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(SelectIdsDTO dto){
        // 根据id查询
        CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty());
        List<FaceInfo> faceInfoList = listByIds(dto.getIds());
        if (faceInfoList.isEmpty()) {
            return;
        }
        for (FaceInfo faceInfo : faceInfoList) {
            try {
                FaceLibrary faceLibrary = faceLibraryMapper.selectOneById(faceInfo.getLibraryId());
                EdgeBox edgeBox = edgeBoxMapper.selectOneById(faceLibrary.getBoxId());
                aiBoxRequestUtil.deleteFaceInfo(edgeBox.getIp(), edgeBox.getPort(), faceInfo.getFaceSign(), faceLibrary.getName());
            }catch (Exception e)
            {
                log.error("AI盒子删除人脸库失败, faceInfoName: {}", faceInfo.getName(), e);
                throw new BusinessException(AdminResponseEnum.OPERATION_FAIL,null, "同步删除AI盒子数据失败，请重试");
            }
        }
        removeByIds(dto.getIds());
        faceImageService.removeByFaceIds(dto.getIds());
    }

    @Override
    public FaceInfoVO detail(Object id){
        FaceInfo ryFaceInfo = getById((Serializable) id);
        CommonResponseEnum.INVALID_ID.assertNull(ryFaceInfo);
        return BeanCopyUtils.copy(ryFaceInfo, FaceInfoVO.class);
    }

    @SneakyThrows
    @Override
    public void importExcel(ImportExcelDTO dto) {
        ExcelResult<FaceInfoImportDTO> excelResult = ExcelUtils.importExcel(dto.getFile().getInputStream(), FaceInfoImportDTO.class, true);
        List<FaceInfoImportDTO> list = excelResult.getList();
        // 入库
        List<FaceInfo> importList = BeanCopyUtils.copyList(list, FaceInfo.class);
        saveBatch(importList);
        List<String> errorList = excelResult.getErrorList();
        String analysis = excelResult.getAnalysis();
        System.out.println(" analysis : " + analysis);
        System.out.println(" isCover : " + dto.getIsCover());
    }

    @SneakyThrows
    @Override
    public void exportExcel(FaceInfoListDTO dto, HttpServletResponse response) {
        List<FaceInfoVO> list = list(dto);
        String fileName = "人脸信息表模板";
        OutputStream os = FileUtils.getOutputStream(response, fileName + ".xlsx");
        ExcelUtils.exportExcel(list, "人脸信息表", FaceInfoVO.class, os);
    }

    @Override
    @Transactional
    public void removeByLibraryIds(List<? extends Serializable> ids) {
        QueryWrapper wrapper = QueryWrapper.create()
            .select()
            .from(FaceInfo.class)
            .in(FaceInfo::getLibraryId, ids);
        List<FaceInfo> faceInfoList = this.list(wrapper);
        if (faceInfoList.isEmpty()) {
            return;
        }
        // 删除关联的人脸图片表数据
        faceImageService.removeByFaceIds(faceInfoList.stream().map(FaceInfo::getId).toList());
        // 删除人脸信息表数据
        removeByIds(faceInfoList.stream().map(FaceInfo::getId).toList());
    }

    private static QueryWrapper buildQueryWrapper(FaceInfoListDTO dto) {
        QueryWrapper wrapper = QueryWrapper.create().from(FaceInfo.class);
        if (Utils.isNotNull(dto.getFaceSign())) {
            wrapper.eq(FaceInfo::getFaceSign, dto.getFaceSign());
        }
        if (Utils.isNotNull(dto.getName())) {
            wrapper.like(FaceInfo::getName, dto.getName());
        }
        if (Utils.isNotNull(dto.getLibraryId())) {
            wrapper.eq(FaceInfo::getLibraryId, dto.getLibraryId());
        }
        if (Utils.isNotNull(dto.getRegisterTimeStart()) && Utils.isNotNull(dto.getRegisterTimeEnd())) {
            wrapper.between(FaceInfo::getRegisterTime, dto.getRegisterTimeStart(), dto.getRegisterTimeEnd());
        }
        return wrapper;
    }
}