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.Product;
import cn.cslg.report.exception.XiaoShiException;
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
 * @Data 2022/12/20
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProductServiceImpl implements IProductService {
    private final ProductMapper productMapper;  //产品的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());

        //检查当前报告是否已有创建的产品 (根据报告id查询产品，1个报告只能创建有1个产品)
        Integer reportId = product.getReportId();
        int count = productMapper.countByReportId(reportId);
        if (count > 0) {
            String message = "新增产品失败，当前报告产品已创建";
            log.info("{}", message);
            throw new XiaoShiException(message);
        }

        //1.产品数据入产品表
        productMapper.insert(product);
        //2.附件数据(如果有附件)入报告系统文件表并返回附件的id集合
        if (files != null && files.size() != 0) {
            List<Integer> fileIds = reportFileService.uploadFiles(files);
            //3.产品productId和附件fileId入产品文件关联表
            assoProductFileService.addAsso(product.getId(), fileIds);
        }
        log.info("新增产品完成");

    }

    /**
     * 修改产品
     *
     * @param productIncludeFilesDTO 产品新数据
     * @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修改产品表数据
        productMapper.update(product);

        //2.根据reportId(报告id)关联查询出产品关联附件的数据信息
        Integer reportId = product.getReportId();
        ProductIncludeFilesVO queryResult = productMapper.getWholeByReportId(reportId);

        //3.取出对象中的附件集合属性，遍历取出原所有附件fileIds
        List<ReportFileStandardVO> oldReportFiles = queryResult.getReportFiles();
        ArrayList<Integer> oldFileIdList = new ArrayList<>();
        for (ReportFileStandardVO reportFile : oldReportFiles) {
            Integer fileId = reportFile.getId();
            oldFileIdList.add(fileId);
        }
        //4.取出对象中的附件集合属性，遍历取出现所有附件fileIds
        List<ReportFileStandardVO> newReportFiles = productIncludeFilesDTO.getReportFiles();
        ArrayList<Integer> newFileIdList = new ArrayList<>();
        for (ReportFileStandardVO reportFile : newReportFiles) {
            Integer fileId = reportFile.getId();
            newFileIdList.add(fileId);
        }
        //5.fileId集合去重，去重后剩下的fileId即为被删除的附件fileId
        oldFileIdList.removeAll(newFileIdList);

        //6.若去重后的原fileId集合仍有长度(即表示剩下了被删除部分的附件)，则删除文件表和产品文件关联表中被删除的附件的数据
        if (oldFileIdList.size() != 0) {
            reportFileService.deleteFiles(oldFileIdList);  //删除文件表中被删除附件的数据
            assoProductFileService.deleteAssoByFileIds(oldFileIdList);  //删除产品文件关联表中被删除附件的数据
        }

        //7.插入新的附件入报告系统文件表中，返回文件id
        if (files != null) {
            List<Integer> fileIds = reportFileService.uploadFiles(files);
            //8.插入新的文件id入产品文件关联表中
            Integer productId = product.getId();
            assoProductFileService.addAsso(productId, fileIds);
        }


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

    }

    /**
     * 根据报告reportId关联查询产品和产品附件数据(产品表、产品文件关联表、报告系统文件表)
     *
     * @param reportId 报告id
     * @return 返回查询到的产品和产品附件数据对象
     */
    @Override
    public ProductIncludeFilesVO getProduct(Integer reportId) {
        log.info("开始处理【查询产品】的业务，参数为：{}", reportId);
        ProductIncludeFilesVO queryResult = productMapper.getWholeByReportId(reportId);
        if (queryResult == null) {
            log.info("查询成功，产品不存在");
        }
        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("删除产品失败，产品不存在");
        }

    }
}
