package com.xinyilu.system.service.personalcheckreport.impl;

import com.xinyilu.common.config.XinYiLuConfig;
import com.xinyilu.common.constant.Constants;
import com.xinyilu.common.core.domain.AjaxResult;
import com.xinyilu.common.enums.CheckStatusEnum;
import com.xinyilu.common.exception.ServiceException;
import com.xinyilu.common.utils.DateUtils;
import com.xinyilu.common.utils.SecurityUtils;
import com.xinyilu.common.utils.StringUtils;
import com.xinyilu.common.utils.codes.GenerateSystemCodeUtil;
import com.xinyilu.common.utils.file.FileUploadUtils;
import com.xinyilu.common.utils.file.FileUtils;
import com.xinyilu.system.domain.checkreport.StudentPersonalReportDTO;
import com.xinyilu.system.domain.dto.PersonalExamineAndApproveDTO;
import com.xinyilu.system.domain.dto.UploadPersonalCheckReportDTO;
import com.xinyilu.system.domain.personalcheckreport.PersonalCheckReport;
import com.xinyilu.system.domain.vo.personalcheckreport.ExistCheckReportVO;
import com.xinyilu.system.domain.vo.personalcheckreport.PersonalCheckReportVO;
import com.xinyilu.system.domain.vo.personalcheckreport.PersonalExamineAndApproveVO;
import com.xinyilu.system.mapper.checkreport.CheckReportMapper;
import com.xinyilu.system.mapper.personalcheckreport.PersonalCheckReportMapper;
import com.xinyilu.system.service.personalcheckreport.IPersonalCheckReportService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * 个人体质检测报告Service业务层处理
 *
 * @author xinyilu
 * @date 2022-09-22
 */
@Slf4j
@Service
public class PersonalCheckReportServiceImpl implements IPersonalCheckReportService {
    @Resource
    private PersonalCheckReportMapper personalCheckReportMapper;
    @Resource
    private XinYiLuConfig xinYiLuConfig;
    @Resource
    private CheckReportMapper checkReportMapper;
    @Resource
    private GenerateSystemCodeUtil generateSystemCodeUtil;

    /**
     * 查询个人体质检测报告
     *
     * @param id 个人体质检测报告主键
     * @return 个人体质检测报告
     */
    @Override
    public PersonalCheckReport selectPersonalCheckReportById(Long id) {
        return personalCheckReportMapper.selectPersonalCheckReportById(id);
    }

    /**
     * 查询个人体质检测报告列表
     *
     * @param personalCheckReport 个人体质检测报告
     * @return 个人体质检测报告
     */
    @Override
    public List<PersonalCheckReportVO> selectPersonalCheckReportList(PersonalCheckReportVO personalCheckReport) {
        return personalCheckReportMapper.selectPersonalCheckReportList(personalCheckReport);
    }

    /**
     * 个人体质检测报告,一键审核功能-列表(无分页)
     *
     * @param personalCheckReport 个人体质检测报告
     * @return 个人体质检测报告集合
     */
    @Override
    public List<PersonalExamineAndApproveDTO> selectPersonalCheckReportListAll(PersonalExamineAndApproveVO personalCheckReport) {
        //查询所有报告
        List<PersonalExamineAndApproveDTO> checkReportAll = personalCheckReportMapper.selectPersonalCheckReportAll(personalCheckReport);
        //查询个人体表里面已审批的报告
        personalCheckReport.setCheckStatus(CheckStatusEnum.CHECK.getStatus());
        List<PersonalExamineAndApproveDTO> andApproveVOList = personalCheckReportMapper.selectApprovedReportPass(personalCheckReport);
        //求出差集,返回数据
        Collection<PersonalExamineAndApproveDTO> subtract = CollectionUtils.subtract(checkReportAll, andApproveVOList);
        return subtract.stream().filter(Objects::nonNull).peek(s -> s.setCheckReportType(Constants.PERSONAL)).collect(Collectors.toList());
    }

    /**
     * 新增个人体质检测报告
     *
     * @param personalCheckReport 个人体质检测报告
     * @return 结果
     */
    @Override
    public int insertPersonalCheckReport(PersonalCheckReport personalCheckReport) {
        personalCheckReport.setCreateTime(DateUtils.getNowDate());
        return personalCheckReportMapper.insertPersonalCheckReport(personalCheckReport);
    }

    /**
     * 修改个人体质检测报告
     *
     * @param personalCheckReport 个人体质检测报告
     * @return 结果
     */
    @Override
    public AjaxResult updatePersonalCheckReport(PersonalCheckReport personalCheckReport) {
        //修改时间，修改时间，审核人，审核时间
        personalCheckReport.setUpdateTime(DateUtils.getNowDate());
        personalCheckReport.setUpdateBy(SecurityUtils.getUsername());
        personalCheckReport.setCheckUserId(SecurityUtils.getUserId());
        personalCheckReport.setCheckTime(LocalDateTime.now());
        int checkReport = personalCheckReportMapper.updatePersonalCheckReport(personalCheckReport);
        if (checkReport <= 0) {
            return AjaxResult.error("审核失败，请联系管理员！");
        }
        return AjaxResult.success();
    }

    /**
     * 批量删除个人体质检测报告
     *
     * @param ids 需要删除的个人体质检测报告主键
     * @return 结果
     */
    @Override
    public int deletePersonalCheckReportByIds(Long[] ids) {
        return personalCheckReportMapper.deletePersonalCheckReportByIds(ids);
    }

    /**
     * 删除个人体质检测报告信息
     *
     * @param id 个人体质检测报告主键
     * @return 结果
     */
    @Override
    public int deletePersonalCheckReportById(Long id) {
        return personalCheckReportMapper.deletePersonalCheckReportById(id);
    }

    /**
     * 审核报告预览下载
     *
     * @param response 响应消息
     * @param id       个人体质检测报告id
     */
    @Override
    public void downLoadAddress(Long id, HttpServletResponse response) {
        PersonalCheckReport personalCheckReport = personalCheckReportMapper.selectPersonalCheckReportById(id);
        if (Objects.isNull(personalCheckReport) || StringUtils.isBlank(personalCheckReport.getDownloadAddress())) {
            throw new ServiceException("当前报告信息不存在！");
        }
        //检验文件是否可以下载
        String reportName = StringUtils.isBlank(personalCheckReport.getReportName()) ? "" : personalCheckReport.getReportName();
        if (FileUtils.checkAllowDownload(reportName)) {
            throw new ServiceException(StringUtils.format("文件名称({})非法，不允许下载。 ", reportName));
        }
        //文件路径
        String filePath = XinYiLuConfig.getProfile() + personalCheckReport.getDownloadAddress().replaceAll("/profile", "");
        try {
            //下载
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            FileUtils.setAttachmentResponseHeader(response, reportName);
            FileUtils.writeBytes(filePath, response.getOutputStream());
        } catch (Exception exception) {
            log.error("个人检测报告下载异常，报告名称：{}, 异常信息为：{}", reportName, exception.getMessage());
            throw new ServiceException("个人检测报告下载异常，请联系管理员！");
        }
    }

    /**
     * 判断个人检测报告是否存在
     *
     * @param studentId 学生id
     * @param batchCode 批次编号
     * @return 结果
     */
    @Override
    public AjaxResult existCheckReport(Long studentId, String batchCode) {
        ExistCheckReportVO existCheckReportVO = personalCheckReportMapper.getPersonalCheckReportInfo(studentId, batchCode);
        if (Objects.isNull(existCheckReportVO)) {
            ExistCheckReportVO vo = new ExistCheckReportVO();
            vo.setExistFlag(false);
            return AjaxResult.success(vo);
        }
        existCheckReportVO.setExistFlag(true);
        return AjaxResult.success(existCheckReportVO);
    }

    /**
     * 上传个人学生报告信息
     *
     * @param checkReportDTO 输入参数实体类
     * @return 上传结果
     * @throws Exception 异常信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult uploadPersonalCheckReport(UploadPersonalCheckReportDTO checkReportDTO) throws Exception {
        //文件路径
        String checkReportPath = XinYiLuConfig.getProfile() + xinYiLuConfig.getCheckReportUrl() + "/" + checkReportDTO.getStudentId() + "/" + checkReportDTO.getBatchCode();
        File checkReportFile = new File(checkReportPath);
        if (!checkReportFile.exists()) {
            //文件路径不存在，创建文件路径
            boolean createMkdirs = checkReportFile.mkdirs();
            if (BooleanUtils.isFalse(createMkdirs)) {
                throw new ServiceException("个人检测报告文件目录创建失败！");
            }
        }
        //报告名称
        String checkReportName = checkReportPath + "/" + checkReportDTO.getStudentName() + "_" + checkReportDTO.getBatchCode() + "_幼儿体质检测报告书.pdf";
        File checkReportNameFile = new File(checkReportName);
        if (checkReportNameFile.exists()) {
            //文件名称已存在，删除文件
            boolean delete = checkReportNameFile.delete();
            if (BooleanUtils.isFalse(delete)) {
                throw new ServiceException("个人检测报告文件删除失败！");
            }
            //删除数据库报告信息
            int deleteStudentReportCount = checkReportMapper.deleteStudentPersonReportInfo(checkReportDTO.getStudentId(), checkReportDTO.getBatchCode());
            if (deleteStudentReportCount <= 0) {
                throw new ServiceException("删除个人检测报告信息失败，请联系管理员！");
            }
        }
        //文件保存到本地路径中
        FileUploadUtils.uploadCheckReport(checkReportName, checkReportDTO.getPersonalFile(), null);
        //将生成报告信息保存到数据库中
        String reportFileName = checkReportDTO.getStudentName() + "_" + checkReportDTO.getBatchCode() + "_幼儿体质检测报告书.pdf";
        String downAddress = "/profile" + xinYiLuConfig.getCheckReportUrl() + "/" + checkReportDTO.getStudentId() + "/" + checkReportDTO.getBatchCode() + "/" + reportFileName;
        StudentPersonalReportDTO dto = buildStudentReportInfo(checkReportDTO, reportFileName, downAddress);
        int insertStudentReportCount = checkReportMapper.insertStudentPersonReportInfo(dto);
        if (insertStudentReportCount <= 0) {
            throw new ServiceException("保存个人检测报告信息失败，请联系管理员！");
        }
        return AjaxResult.success();
    }

    /**
     * 构建个人学生报告信息
     *
     * @param checkReportDTO 输入参数
     * @param reportName     报告名称
     * @param downAddress    报告下载地址
     * @return 个人报告信息结果
     */
    private StudentPersonalReportDTO buildStudentReportInfo(UploadPersonalCheckReportDTO checkReportDTO,
                                                            String reportName, String downAddress) {
        return StudentPersonalReportDTO.builder()
                .studentId(checkReportDTO.getStudentId()).batchCode(checkReportDTO.getBatchCode())
                .reportCode(Constants.STUDENT_CHECK_REPORT_PREFIX + generateSystemCodeUtil.generateSystemCode(Constants.STUDENT_CHECK_REPORT_PREFIX))
                .reportName(reportName).downloadAddress(downAddress).checkStatus(checkReportDTO.getCheckStatus())
                .checkUserId(SecurityUtils.getUserId()).checkTime(LocalDateTime.now())
                .delFlag(0).createTime(LocalDateTime.now()).createBy(SecurityUtils.getUsername())
                .build();
    }
}
