package cn.cslg.report.service.impl;

import cn.cslg.report.common.model.dto.ProductDTO;
import cn.cslg.report.common.model.dto.ProductIncludeFilesDTO;
import cn.cslg.report.common.model.vo.PersonnelVO;
import cn.cslg.report.common.model.vo.ProductIncludeFilesVO;
import cn.cslg.report.common.model.vo.ReportFileStandardVO;
import cn.cslg.report.common.utils.CacheUtils;
import cn.cslg.report.common.utils.SecurityUtils.LoginUtils;
import cn.cslg.report.entity.AssoProductFile;
import cn.cslg.report.entity.Product;
import cn.cslg.report.exception.XiaoShiException;
import cn.cslg.report.mapper.AssoProductFileMapper;
import cn.cslg.report.mapper.ProductMapper;
import cn.cslg.report.service.IAssoProductFileService;
import cn.cslg.report.service.IProductService;
import cn.cslg.report.service.business.ReportFileService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.List;

/**
 * 产品的Service层实现类
 *
 * @Author chenyu
 * @Date 2022/12/20
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProductServiceImpl implements IProductService {
    private final ProductMapper productMapper;  //产品表的Mapper层装配
    private final AssoProductFileMapper assoProductFileMapper;  //产品文件关联表的Mapper层装配
    private final ReportFileService reportFileService;  //报告系统文件的Service层装配
    private final IAssoProductFileService assoProductFileService;  //产品文件关联的Service层装配
    private final CacheUtils cacheUtils;
    private final LoginUtils loginUtils;

    /**
     * 新增产品
     *
     * @param productDTO 新增产品的前端传输DTO数据对象
     * @param files      产品附件
     */
    @Override
    public void addProduct(ProductDTO productDTO, List<MultipartFile> files) {
        log.info("开始处理【新增产品】的业务，参数为：{}, {}", productDTO, files);

        //DTO赋值给产品表实体类
        Product product = new Product();
        BeanUtils.copyProperties(productDTO, product);
        //获取当前登陆人信息
        PersonnelVO personnelVO = cacheUtils.getLoginUser(loginUtils.getId());
        //给实体类赋值登陆人id和姓名
        product.setCreatePersonId(personnelVO.getId())
                .setCreatePersonName(personnelVO.getName());

        //1.检查当前报告产品是否已存在 (根据报告reportId统计数量)
        Integer reportId = product.getReportId();
        log.info("检查当前报告产品是否已存在");
        int count = productMapper.countByReportId(reportId);
        if (count > 0) {
            String message = "新增产品失败，当前报告产品已存在";
            log.info("{}", message);
            throw new XiaoShiException(message);
        }

        //2.数据入产品表
        log.info("数据入产品表");
        int rows = productMapper.insert(product);
        if (rows != 1) {
            String message = "新增产品失败，服务器忙请稍后再试";
            log.info("数据入产品表失败，{}", message);
            throw new XiaoShiException(message);
        }

        //3.数据入报告系统文件表(并返回附件的id集合)
        if (files != null && files.size() != 0) {
            log.info("数据入报告系统文件表");
            List<Integer> fileIds = reportFileService.uploadFiles(files);
            //4.数据入产品文件关联表
            Integer productId = product.getId();
            //之前是直接调用产品文件关联的Service层业务：assoProductFileService.addAsso(productId, fileIds); 现在自己敲👇
            ArrayList<AssoProductFile> assoProductFiles = new ArrayList<>();
            for (Integer fileId : fileIds) {
                AssoProductFile assoProductFile = new AssoProductFile()
                        .setProductId(productId)
                        .setFileId(fileId)
                        .setFileUseType(0);
                assoProductFiles.add(assoProductFile);
            }
            log.info("数据入产品文件关联表");
            rows = assoProductFileMapper.insertBatch(assoProductFiles);
            if (rows != fileIds.size()) {
                String message = "新增产品失败，服务器忙请稍后再试";
                log.info("数据入产品文件关联表失败，{}", message);
                throw new XiaoShiException(message);
            }
        }

        log.info("新增产品完成");

    }

    /**
     * 修改产品
     *
     * @param productIncludeFilesDTO 修改产品的前端传输DTO数据对象
     * @param files                  产品附件
     */
    @Override
    public void updateProduct(ProductIncludeFilesDTO productIncludeFilesDTO, List<MultipartFile> files) {
        log.info("开始处理【修改产品】的业务，参数为：{}, {}", productIncludeFilesDTO, files);

        //DTO赋值给产品表实体类
        Product product = new Product();
        BeanUtils.copyProperties(productIncludeFilesDTO, product);

        //1.根据id修改产品表数据
        log.info("修改产品表数据");
        int rows = productMapper.update(product);
        if (rows != 1) {
            String message = "修改产品失败，服务器忙请稍后再试";
            log.info("修改产品表数据失败，{}", message);
            throw new XiaoShiException(message);
        }

        //根据报告reportId关联查询产品表、产品文件关联表、报告系统文件表三表，获得产品和原附件数据
        Integer reportId = product.getReportId();
        log.info("根据报告reportId关联产品表、产品文件关联表、报告系统文件表三表，查询产品和附件的数据");
        ProductIncludeFilesVO queryResult = productMapper.getWholeByReportId(reportId);

        //从产品和原附件数据中获得原附件数据，遍历原附件，取出所有原附件fileId存入集合
        List<ReportFileStandardVO> oldReportFiles = queryResult.getReportFiles();
        ArrayList<Integer> oldFileIds = new ArrayList<>();
        for (ReportFileStandardVO oldReportFile : oldReportFiles) {
            Integer oldFileId = oldReportFile.getId();
            oldFileIds.add(oldFileId);
        }
        //从DTO中获得新的原附件数据，遍历新的原附件，取出所有新的原附件fileId存入集合
        List<ReportFileStandardVO> newOldReportFiles = productIncludeFilesDTO.getReportFiles();
        ArrayList<Integer> newOldFileIds = new ArrayList<>();
        for (ReportFileStandardVO newOldReportFile : newOldReportFiles) {
            Integer newOldFileId = newOldReportFile.getId();
            newOldFileIds.add(newOldFileId);
        }
        //fileId集合去重，去重后留下的fileId即为被删除的原附件fileId
        oldFileIds.removeAll(newOldFileIds);

        //如果去重后的oldFileIds仍有长度(即表示集合中留下的被删除的部分原附件fileId)，则删除产品文件关联表和报告系统文件表中被删除的部分原附件fileId相关数据
        if (oldFileIds.size() != 0) {
            //2.删除产品文件关联表中被删除附件的数据
            log.info("删除产品文件关联表数据");
            rows = assoProductFileMapper.deleteByFileIds(oldFileIds);
            if (rows != oldFileIds.size()) {
                String message = "修改产品失败，服务器忙请稍后再试";
                log.info("删除产品文件关联表数据失败，{}", message);
                throw new XiaoShiException(message);
            }
            //2.删除报告系统文件表中被删除附件的数据
            log.info("删除报告系统文件表数据");
            reportFileService.deleteFiles(oldFileIds);
        }

        //如果前端传来的files附件不为null(即表示新增了若干附件)，则新附件数据入报告系统文件表和产品文件关联表
        if (files != null) {
            //3.新的附件入报告系统文件表，返回附件fileId
            log.info("数据入报告系统文件表");
            List<Integer> fileIds = reportFileService.uploadFiles(files);
            //3.新的附件fileId入产品文件关联表
            Integer productId = product.getId();
            ArrayList<AssoProductFile> assoProductFiles = new ArrayList<>();
            for (Integer fileId : fileIds) {
                AssoProductFile assoProductFile = new AssoProductFile()
                        .setProductId(productId)
                        .setFileId(fileId)
                        .setFileUseType(0);
                assoProductFiles.add(assoProductFile);
            }
            log.info("数据入产品文件关联表");
            rows = assoProductFileMapper.insertBatch(assoProductFiles);
            if (rows != assoProductFiles.size()) {
                String message = "修改产品失败，服务器忙请稍后再试";
                log.info("数据入产品文件关联表失败，{}", message);
                throw new XiaoShiException(message);
            }
        }

        log.info("产品修改完成");

    }

    /**
     * 根据报告reportId关联查询产品和产品附件数据(产品表、产品文件关联表、报告系统文件表)
     *
     * @param reportId 报告id
     * @return 返回查询到的产品和产品附件数据对象
     */
    @Override
    public ProductIncludeFilesVO getProduct(Integer reportId) {
        log.info("开始处理【查询产品】的业务，参数为：{}", reportId);
        ProductIncludeFilesVO queryResult = productMapper.getWholeByReportId(reportId);
        return queryResult;
    }

    /**
     * 根据报告reportId删除产品及所有关联数据
     *
     * @param reportId 报告id
     */
    @Override
    public void deleteProduct(Integer reportId) {
        log.info("开始处理【删除产品】的业务，参数为：{}", reportId);
        //1.根据产品productId删除产品文件关联表数据：先根据报告id关联查询产品关联附件的数据，取出产品productId
        ProductIncludeFilesVO queryResult = this.getProduct(reportId);
        if (queryResult != null) {
            Integer productId = queryResult.getId();
            assoProductFileService.deleteAssoByProductId(productId);
            //2.根据附件fileId集合删除报告系统文件表数据：先从产品关联附件的数据中取出附件数据，遍历附件取出附件fileId存入集合
            List<ReportFileStandardVO> reportFiles = queryResult.getReportFiles();
            ArrayList<Integer> list = new ArrayList<>();
            for (ReportFileStandardVO reportFile : reportFiles) {
                Integer fileId = reportFile.getId();
                list.add(fileId);
            }
            reportFileService.deleteFiles(list);
            //3.根据报告reportId删除产品表数据
            productMapper.deleteByReportId(reportId);
            log.info("产品删除完成");
        } else {
            log.info("删除产品失败，产品不存在");
        }

    }
}
