package com.casic.missiles.service.Impl.business;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.casic.missiles.dto.ReturnDTO;
import com.casic.missiles.dto.ReturnUtil;
import com.casic.missiles.dto.business.outsource.OrderSampleDTO;
import com.casic.missiles.dto.business.outsource.OutsourceCertificateImportDTO;
import com.casic.missiles.dto.business.outsource.OutsourceCertificateListRequest;
import com.casic.missiles.dto.business.outsource.OutsourceCertificateListResponse;
import com.casic.missiles.enums.BusinessExceptionEnum;
import com.casic.missiles.exception.BusinessException;
import com.casic.missiles.mapper.business.BusinessOrderSampleRelationMapper;
import com.casic.missiles.mapper.business.BusinessOutsourceCertificateMapper;
import com.casic.missiles.mapper.business.BusinessOutsourcerInfoMapper;
import com.casic.missiles.model.business.BusinessOutsourceCertificate;
import com.casic.missiles.model.business.BusinessOutsourcerInfo;
import com.casic.missiles.service.business.IBusinessOutsourceCertificateService;
import com.casic.missiles.service.listeners.CommonExcelListener;
import com.casic.missiles.utils.FileUtil;
import com.casic.missiles.utils.MinioUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

import static com.casic.missiles.utils.FileUtil.getMultipartFile;

/**
 * <p>
 * 分包检定证书表 服务实现类
 * </p>
 *
 * @author wangpeng
 * @since 2023-03-23
 */
@Service
public class BusinessOutsourceCertificateServiceImpl extends ServiceImpl<BusinessOutsourceCertificateMapper, BusinessOutsourceCertificate> implements IBusinessOutsourceCertificateService {
    @Autowired
    private BusinessOutsourceCertificateMapper certificateMapper;
    @Autowired
    private BusinessOrderSampleRelationMapper orderSampleRelationMapper;
    @Autowired
    private BusinessOutsourcerInfoMapper outsourcerInfoMapper;
    @Resource
    private MinioUtil minioUtil;

    @Override
    public Page<OutsourceCertificateListResponse> listPage(OutsourceCertificateListRequest request, Page<OutsourceCertificateListResponse> page) {
        Page<OutsourceCertificateListResponse> infoPage = certificateMapper.selectListPage(page, request);
        if(Objects.isNull(infoPage) || CollectionUtils.isEmpty(infoPage.getRecords())){
            return new Page<>();
        }
        return infoPage;
    }

    @Override
    public List<OutsourceCertificateListResponse> list(OutsourceCertificateListRequest request) {
        List<OutsourceCertificateListResponse> list = certificateMapper.selectList(request);
        if(CollectionUtils.isEmpty(list)){
            return new ArrayList<>();
        }
        return list;
    }

    @Override
    public List<OutsourceCertificateListResponse> listByCertificateIds(List<Long> ids) {
        List<OutsourceCertificateListResponse> list = certificateMapper.selectListByCertificateIds(ids);
        if(CollectionUtils.isEmpty(list)){
            return new ArrayList<>();
        }
        return list;
    }

    @Override
    public ReturnDTO addCertificate(BusinessOutsourceCertificate certificate) {
        if(certificateMapper.insert(certificate) > 0){
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public ReturnDTO updateCertificate(BusinessOutsourceCertificate certificate) {
        if(certificateMapper.updateById(certificate) > 0){
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    @Transactional
    public ReturnDTO batchImport(MultipartFile file) throws IOException {
        //获取文件输入流，压缩文件直接读取
        InputStream in = new BufferedInputStream(file.getInputStream());
        ZipInputStream zin = new ZipInputStream(in, Charset.forName("GBK"));
        //MultipartFile转File，外层zip
        File realFile = FileUtil.multipartFileToFile(file);
        ZipFile zipFile = new ZipFile(realFile, Charset.forName("GBK"));
        BufferedInputStream bs = new BufferedInputStream(zin);
        ZipEntry ze;
        ZipEntry eze = null;
        List<MultipartFile> multipartFileList = new ArrayList<>();
        try {
            //读取zip包中pdf证书文件
            while ((ze = zin.getNextEntry()) != null) {
                if (ze.isDirectory()) {
                    continue;
                }
                if (ze.toString().endsWith("pdf")) {
                    InputStream inputStream = zipFile.getInputStream(ze);
                    //File转MultipartFile，zip内部文件
                    MultipartFile multipartFile = getMultipartFile(inputStream, ze.getName());
                    multipartFileList.add(multipartFile);
                }
                if (ze.toString().endsWith("xlsx") || ze.toString().endsWith("xls")) {
                    eze = ze;
                }
            }
            if(CollectionUtils.isEmpty(multipartFileList) || Objects.isNull(eze)){
                //无证书或证书文件非pdf或无Excel
                throw new BusinessException(BusinessExceptionEnum.OUTSOURCE_CERTIFICATE_NO_FILES);
            }
            List<String> minioNameList = minioUtil.upload(multipartFileList.toArray(new MultipartFile[multipartFileList.size()]));
            //Map：pdf文件名-minio上传文件名
            Map<String, String> map = new HashMap<>();
            for (int i = 0; i < minioNameList.size(); i++) {
                map.put(multipartFileList.get(i).getOriginalFilename(), minioNameList.get(i));
            }

            //读取zip包中excel文件
            InputStream inputStream = zipFile.getInputStream(eze);
            //转换为MultipartFile
            MultipartFile excelFile = FileUtil.getMultipartFile(inputStream, eze.getName());
            //解析excel文件，对应文件名转换minio上传文件名，批量存储
            CommonExcelListener<OutsourceCertificateImportDTO> listener = new CommonExcelListener<>();
            EasyExcel.read(excelFile.getInputStream(), OutsourceCertificateImportDTO.class, listener)
                    .headRowNumber(1).autoTrim(true).sheet(0).doRead();
            List<OutsourceCertificateImportDTO> certificateImportList = listener.getList();
            if(CollectionUtils.isEmpty(certificateImportList)){
                throw new BusinessException(BusinessExceptionEnum.OUTSOURCE_CERTIFICATE_NO_DATA);
            }
            List<BusinessOutsourceCertificate> resultList = new ArrayList<>();
            certificateImportList.forEach(cert -> {
                if(StringUtils.isEmpty(cert.getCertificateCode()) || StringUtils.isEmpty(cert.getCertificateName())
                        || StringUtils.isEmpty(cert.getCertificateName()) || StringUtils.isEmpty(cert.getSampleNo())
                        || StringUtils.isEmpty(cert.getOutsourcerNo()) || StringUtils.isEmpty(cert.getCertificateFileStrings())){
                    throw new BusinessException(BusinessExceptionEnum.OUTSOURCE_CERTIFICATE_NO_DATA_ITEM);
                }
                //样品编号获取样品id、分包方编号获取分包方id
                OrderSampleDTO orderSampleDTO = orderSampleRelationMapper.selectIdBySampleNo(cert.getSampleNo());
                QueryWrapper<BusinessOutsourcerInfo> wrapper = new QueryWrapper<>();
                wrapper.eq("outsourcer_no", cert.getOutsourcerNo());
                BusinessOutsourcerInfo businessOutsourcerInfo = outsourcerInfoMapper.selectOne(wrapper);
                List<String> excelFileList = Arrays.asList(cert.getCertificateFileStrings().split(";"));
                if(Objects.isNull(orderSampleDTO) || Objects.isNull(businessOutsourcerInfo) || CollectionUtils.isEmpty(excelFileList)){
                    throw new BusinessException(BusinessExceptionEnum.OUTSOURCE_CERTIFICATE_INCORRECT_DATA_ITEM);
                }
                excelFileList.forEach(f -> {
                    BusinessOutsourceCertificate certificate = new BusinessOutsourceCertificate();
                    certificate.setCertificateCode(cert.getCertificateCode());
                    certificate.setCertificateName(cert.getCertificateName());
                    certificate.setOutsourcerId(businessOutsourcerInfo.getId());
                    certificate.setOrderId(orderSampleDTO.getOrderId());
                    certificate.setSampleId(orderSampleDTO.getSampleId());
                    certificate.setCertificateFile(map.get(f));
                    //certificate.setOriginalRecordFile();
                    //certificate.setIssuanceDate();
                    //certificate.setExpirationDate();
                    resultList.add(certificate);
                });
            });
            if(!this.saveBatch(resultList)){
                throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
            }
        }finally {
            in.close();
            zin.closeEntry();
            zin.close();
            bs.close();
        }
        return ReturnUtil.success();
    }

}
