package digital.laboratory.platform.inspection.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deepoove.poi.xwpf.NiceXWPFDocument;
import digital.laboratory.platform.common.oss.service.OssFile;
import digital.laboratory.platform.inspection.enums.TestRecordFileUrl;
import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto;
import digital.laboratory.platform.inspection.entity.TestRecordInstrumentCondition;
import digital.laboratory.platform.inspection.enums.TestRecordArgumentType;
import digital.laboratory.platform.inspection.mapper.TestRecordInstrumentConditionMapper;
import digital.laboratory.platform.inspection.mapper.TestRecordMapper;
import digital.laboratory.platform.inspection.mapper.TestTemplateMapper;
import digital.laboratory.platform.inspection.service.*;
import digital.laboratory.platform.inspetion.api.vo.TestRecordVo;
import digital.laboratory.platform.inspection.vo.TestTemplateVo;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

@Service
@SuppressWarnings("all")
public class TestRecordInstrumentConditionServiceImpl extends ServiceImpl<TestRecordInstrumentConditionMapper, TestRecordInstrumentCondition> implements TestRecordInstrumentConditionService {

    @Resource
    private TestRecordService testRecordService;
    @Resource
    private TestRecordMapper testRecordMapper;
    @Resource
    private TestTemplateService testTemplateService;
    @Resource
    private TestTemplateMapper testTemplateMapper;
    @Resource
    private SampleInfoService sampleInfoService;
    @Resource
    private OssFile ossFile;
    @Resource
    private EntrustInfoService entrustInfoService;
    private final String fileName = "仪器条件.docx";

    /**
     * 新增实验仪器条件
     *
     * @param testRecordInstrumentCondition
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public TestRecordInstrumentCondition addInstrumentCondition(TestRecordInstrumentCondition testRecordInstrumentCondition) {
        testRecordInstrumentCondition.setId(IdWorker.get32UUID().toUpperCase());
        boolean ret = testRecordService.updateTestRecordArgument(testRecordInstrumentCondition.getTestId(), testRecordInstrumentCondition.getId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_INSTRUMENT_CONDITION.getType(), 1);
        return this.save(testRecordInstrumentCondition) && ret ? testRecordInstrumentCondition : null;
    }

    /**
     * 删除仪器条件
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delInstrumentCondition(String id) {
        Integer opCode = -1;//表示从实验中删除
        TestRecordInstrumentCondition instrumentCondition = this.getById(id);
        List<TestRecordVo> testRecordList = testRecordMapper.getTestRecordMapList(new LambdaQueryWrapper());
        boolean ret = testRecordService.updateTestRecordArgument(instrumentCondition.getTestId(), instrumentCondition.getId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_INSTRUMENT_CONDITION.getType(), opCode);
        return this.removeById(id) && ret;
    }

    /**
     * 向实验添加仪器条件
     *
     * @param testRecordInstrumentCondition
     * @return
     */
    @Override
    public TestRecordInstrumentCondition updateInstrumentCondition(TestRecordInstrumentCondition testRecordInstrumentCondition) {
        return this.updateById(testRecordInstrumentCondition) ? testRecordInstrumentCondition : null;
    }

    /**
     * 通过实验ID获取这个实验的仪器条件
     *
     * @param testId
     * @return
     */
    @Override
    public TestRecordInstrumentCondition getInstrumentConditionByTestId(String testId) {
        return baseMapper.getTestRecordInstrumentConditionVoMapByTestId(testId);
    }

    /**
     * 为模板添加或移除仪器条件
     *
     * @param testRecordArgumentDto
     * @return
     */
    @Override
    public boolean useInstrumentConditionToTemplate(TestRecordArgumentDto testRecordArgumentDto) {
        return testTemplateService.updateTestTemplate(testRecordArgumentDto.getTemplateId(), testRecordArgumentDto.getArgumentId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_INSTRUMENT_CONDITION.getType(), testRecordArgumentDto.getOpCode());
    }

    /**
     * 复制仪器条件
     *
     * @param idList 仪器条件ID集合
     * @param testId
     * @return
     */
    @Override
    public List<String> copyCondition(List<String> idList, String testId) {
        ArrayList<String> newIdList = new ArrayList<>();
        ArrayList<TestRecordInstrumentCondition> instrumentConditions = new ArrayList<>();
        List<TestRecordInstrumentCondition> list = this.list(new LambdaQueryWrapper<TestRecordInstrumentCondition>().in(TestRecordInstrumentCondition::getId, idList));
        for (TestRecordInstrumentCondition testRecordInstrumentConditionVo : list) {
            TestRecordInstrumentCondition newTestRecordInstrumentCondition = new TestRecordInstrumentCondition();
            newTestRecordInstrumentCondition.setConditionData(testRecordInstrumentConditionVo.getConditionData());
            newTestRecordInstrumentCondition.setBusinessFlag(testRecordInstrumentConditionVo.getBusinessFlag());
            newTestRecordInstrumentCondition.setTestId(testId);
            newTestRecordInstrumentCondition.setId(IdWorker.get32UUID().toUpperCase());
            newIdList.add(newTestRecordInstrumentCondition.getId());
            instrumentConditions.add(newTestRecordInstrumentCondition);
        }
        this.saveBatch(instrumentConditions);
        return newIdList;
    }

    /**
     * 判断这个实验是否生成了仪器条件
     *
     * @param testId
     * @return
     */
    @Override
    public String generatedOrNot(String testId) {
        String path = TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId;
        List<String> fileList = ossFile.fileList(path);
        for (String name : fileList) {
            if (name.equals(fileName)) {
                return path + "/" + fileName;
            }
        }
        return null;
    }

    /**
     * 为实验生成仪器条件模板
     *
     * @param testId
     * @param type   1:生物样本仪器条件 -1 ：缴获物仪器条件
     * @return
     * @throws Exception
     */
    @Override
    public boolean createConditionWordByTest(String testId) throws Exception {
        TestRecordVo vo = testRecordMapper.getTestRecordMapById(testId);
        String businessType = vo.getBusinessType();
        if (!StringUtils.isNotBlank(businessType)) {
            throw new RuntimeException(String.format("当前还未选择样本，无法确定实验类型，请添加样本后再进行创建!"));
        }
        if (!businessType.startsWith("1")) {
            throw new RuntimeException(String.format("任务或筛查无需创建仪器条件!"));
        }
        String url = "";
        if (businessType.equals("10002")) {//type = 1 代表是生物样本类型的仪器条件
            url = TestRecordFileUrl.TEST_RECORD_BIOLOGICAL_SAMPLE_INSTRUMENT_CONDITION_TEMPLATE.getFileUrl();
        } else {
            url = TestRecordFileUrl.TEST_RECORD_SEIZURE_INSTRUMENT_CONDITION_TEMPLATE.getFileUrl();
        }
        String filePath = TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId + "/" + fileName;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        ossFile.fileGet(url, bos);
        byte[] templateArray = bos.toByteArray();
        ByteArrayInputStream bis = new ByteArrayInputStream(templateArray);
        boolean ret = ossFile.fileSave(filePath, bis);
        bos.close();
        bis.close();
        return ret;
    }

    /**
     * 为模板生成仪器条件模板
     *
     * @param testId
     * @param type   1:生物样本仪器条件 -1 ：缴获物仪器条件
     * @return
     * @throws Exception
     */
    @Override
    public boolean createConditionWordByTemplate(String templateId) throws Exception {
        String url = "";
        TestTemplateVo vo = testTemplateMapper.getTestTemplateMapById(templateId);
        if (vo.getBusinessType().equals("10002")) {//代表是生物样本类型的仪器条件
            url = TestRecordFileUrl.TEST_RECORD_BIOLOGICAL_SAMPLE_INSTRUMENT_CONDITION_TEMPLATE.getFileUrl();
        } else {
            url = TestRecordFileUrl.TEST_RECORD_SEIZURE_INSTRUMENT_CONDITION_TEMPLATE.getFileUrl();
        }
        String filePath = TestRecordFileUrl.TEST_TEMPLATE_CATALOGUE.getFileUrl() + "/" + templateId + "/" + fileName;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        ossFile.fileGet(url, bos);
        byte[] templateArray = bos.toByteArray();
        ByteArrayInputStream bis = new ByteArrayInputStream(templateArray);
        boolean ret = ossFile.fileSave(filePath, bis);
        //创建好后将仪器条件类型存储在实验里面
        bos.close();
        bis.close();
        return ret;
    }

//    /**
//     * 判断是否能够选择这个类型的仪器条件模板
//     *
//     * @param testId
//     * @param type   :  1:生物样本仪器条件 -1 ：缴获物仪器条件
//     */
//    public void comparisonTypeForTest(String testId, Integer type) {
//        TestRecordVo vo = testRecordMapper.getTestRecordMapById(testId);
//        String businessType = vo.getBusinessType();
//        if (StringUtils.isNotBlank(businessType)) {
//            if (!businessType.startsWith("1")) {
//                throw new RuntimeException(String.format("任务或筛查无需创建仪器条件!!!"));
//            }
//            if (businessType.equals("10001") && type != -1) {
//                throw new RuntimeException(String.format("当前选择的仪器条件模板类别与实验类型不匹配!!!"));
//            }
//            if (businessType.equals("10002") && type != 1) {
//                throw new RuntimeException(String.format("当前选择的仪器条件模板类别与实验类型不匹配!!!"));
//            }
//        }
//    }

    /**
     * 获取实验仪器条件的类别
     *
     * @param testId
     * @return
     */
    public Integer getConditionFileType(String testId) {
        TestRecordVo vo = testRecordMapper.getTestRecordMapById(testId);
        List<String> deviceUseCondition = vo.getDeviceUseCondition();
        if (deviceUseCondition != null && deviceUseCondition.size() > 0) {
            return Integer.parseInt(deviceUseCondition.get(0));

        }
        return null;
    }
    /**
     * 为模板创建仪器条件word
     *
     * @param templateId
     * @param testId
     * @throws Exception
     */
    @Override
    public void copyConditionWord(String templateId, String testId) throws Exception {
        // TODO:要先判断是否已经存在仪器条件模板
        List<String> fileNameList = ossFile.fileList(TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId);
        boolean ret = fileNameList.contains(fileName);
        if (ret) {
            String filePath = TestRecordFileUrl.TEST_TEMPLATE_CATALOGUE.getFileUrl() + "/" + templateId + "/" + fileName;
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ossFile.fileGet(TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId + "/" + fileName, bos);
            byte[] templateArray = bos.toByteArray();
            ByteArrayInputStream bis = new ByteArrayInputStream(templateArray);
            ossFile.fileSave(filePath, bis);
            bos.close();
            bis.close();
        }
    }

    /**
     * 将仪器条件内容合并至检验记录中
     *
     * @param testId
     * @throws Exception
     */
    @Override
    public boolean mergeFile(String testId) throws Exception {
        String businessType = testRecordMapper.getTestRecordMapById(testId).getBusinessType();
        if (StringUtils.isNotBlank(businessType) && businessType.equals("10002")) {
            return this.mergeBiologicalSampleFile(testId);
        } else if (StringUtils.isNotBlank(businessType) && businessType.equals("10001")) {
            return this.mergeSeizureFile(testId);
        }
        return false;
    }

    /**
     * 合并生物样本仪器条件与检验记录
     *
     * @param testId
     * @throws Exception
     */
    public boolean mergeBiologicalSampleFile(String testId) throws Exception {
        String filePath = TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId + "/" + fileName;//生物样本仪器条件
        ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
        ossFile.fileGet(filePath, bos1);
        byte[] templateArray1 = bos1.toByteArray();
        ByteArrayInputStream bis1 = new ByteArrayInputStream(templateArray1);
        NiceXWPFDocument sourceDoc = new NiceXWPFDocument(bis1);
        bos1.write(bis1);

        //获取仪器条件表格
        XWPFTable table = sourceDoc.getTables().get(0);

        String templatePath = TestRecordFileUrl.TEST_RECORD_BIOLOGICAL_SAMPLE_TEMPLATE.getFileUrl();//生物样本检验记录模板
        ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
        ossFile.fileGet(templatePath, bos2);
        byte[] templateArray2 = bos2.toByteArray();
        ByteArrayInputStream bis2 = new ByteArrayInputStream(templateArray2);
        NiceXWPFDocument targetDoc = new NiceXWPFDocument(bis2);

        int insertPosition = 1;//替换到第2个段落的表格

        //替换表格
        targetDoc.setTable(insertPosition, table);

//        //删除空白行
//        for (int i = targetDoc.getParagraphs().size() - 1; i >= 0; i--) {
//            XWPFParagraph paragraph = targetDoc.getParagraphs().get(i);
//            if (paragraph.getRuns().isEmpty() || paragraph.getText().trim().isEmpty()) {
//                targetDoc.removeBodyElement(targetDoc.getPosOfParagraph(paragraph));
//            }
//        }
        String temporaryfileName = "生物样本检验记录.docx";
        String temporaryPath = TestRecordFileUrl.TEMPORARY_PATH.getFileUrl() + "/" + temporaryfileName;//临时存储
        FileOutputStream fileOutputStream = new FileOutputStream(temporaryPath);
        targetDoc.write(fileOutputStream);
        fileOutputStream.close();
        File file = new File(temporaryPath);
        FileItem fileItem = this.getMultipartFile(file, file.getName());
        MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
        String ossPath = TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId;
        boolean ret = ossFile.fileUpload(multipartFile, ossPath);
        if (ret) {
            Files.delete(Paths.get(temporaryPath));
        }
        return ret;
    }

    /**
     * 合并缴获物仪器条件与检验记录
     *
     * @param testId
     * @throws Exception
     */
    public boolean mergeSeizureFile(String testId) throws Exception {

        String filePath = TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId + "/" + fileName;//
        ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
        ossFile.fileGet(filePath, bos1);
        byte[] templateArray1 = bos1.toByteArray();
        ByteArrayInputStream bis1 = new ByteArrayInputStream(templateArray1);
        NiceXWPFDocument sourceDoc = new NiceXWPFDocument(bis1);
        bos1.write(bis1);

        //获取仪器条件表格
        XWPFTable table = sourceDoc.getTables().get(0);

        //todo:缴获物检验记录模板
        String templatePath = TestRecordFileUrl.TEST_RECORD_SEIZURE_TEMPLATE.getFileUrl();
        ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
        ossFile.fileGet(templatePath, bos2);
        byte[] templateArray2 = bos2.toByteArray();
        ByteArrayInputStream bis2 = new ByteArrayInputStream(templateArray2);
        NiceXWPFDocument targetDoc = new NiceXWPFDocument(bis2);

        bis2.close();
        bos2.close();
        bis1.close();
        bos1.close();

        int insertPosition = 5;//替换第五个表格之后的表格

        //替换表格
        targetDoc.setTable(insertPosition, table);

        String temporaryfileName = "缴获物检验记录.docx";
        String temporaryPath = TestRecordFileUrl.TEMPORARY_PATH.getFileUrl() + temporaryfileName;//临时存储
        FileOutputStream fileOutputStream = new FileOutputStream(temporaryPath);
        targetDoc.write(fileOutputStream);
        fileOutputStream.close();
        File file = new File(temporaryPath);
        FileItem fileItem = this.getMultipartFile(file, file.getName());
        FileInputStream fileInputStream = new FileInputStream(TestRecordFileUrl.TEMPORARY_PATH.getFileUrl() + temporaryfileName);
        MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
        String ossPath = TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId + "/" + temporaryfileName;
        boolean ret = ossFile.fileSave(ossPath, fileInputStream);
        if (ret) {
            Files.delete(Paths.get(temporaryPath));
        }
        return ret;
    }

    //todo:一个文件类型转换的封装方法
    @Override
    public FileItem getMultipartFile(File file, String fieldName) {
        FileItemFactory factory = new DiskFileItemFactory(16, null);
        FileItem item = factory.createItem(fieldName, "text/plain", true, file.getName());
        int bytesRead = 0;
        byte[] buffer = new byte[8192];
        try {
            FileInputStream fis = new FileInputStream(file);
            OutputStream os = item.getOutputStream();
            while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return item;
    }
}
