package digital.laboratory.platform.inspection.controller;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import digital.laboratory.platform.common.aop.annotation.DlpAccessLimit;
import digital.laboratory.platform.common.core.util.R;
import digital.laboratory.platform.common.mybatis.security.service.DLPUser;
import digital.laboratory.platform.inspetion.api.enums.BusinessType;
import digital.laboratory.platform.inspection.dto.*;
import digital.laboratory.platform.inspection.entity.TestRecordSampleData;
import digital.laboratory.platform.inspection.query.AnalysisTestResultPageQuery;
import digital.laboratory.platform.inspection.query.QueryTestResultPageQuery;
import digital.laboratory.platform.inspection.service.TestRecordSampleDataService;
import digital.laboratory.platform.inspection.utils.TestDataFileUtil;
import digital.laboratory.platform.inspection.utils.datafile.hair.HairSewageCompoundData;
import digital.laboratory.platform.inspection.utils.datafile.nps.NPSDataFileStruct;
import digital.laboratory.platform.inspection.vo.TestRecordSampleDataVO;
import digital.laboratory.platform.inspection.vo.TestResultBusinessVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.ibatis.exceptions.TooManyResultsException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.security.Principal;
import java.util.List;
import java.util.Map;

/**
 * @author xy
 * @version 1.0
 * @title TestRecordSampleDataController   实验数据控制器
 * @description
 * @create 2024/1/19 15:57
 */
@RestController
@RequestMapping("/testRecord_TestData")
@Api(tags = "15-检验记录-实验数据管理服务", description = "检验记录-实验数据管理服务接口")
public class TestRecordSampleDataController {

    @Resource
    private TestRecordSampleDataService testRecordSampleDataService;

    //解析数据文件
    @PostMapping("/parseTestData")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "上传检验数据文件", notes = "上传检验数据文件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "fileTypeCode", value = "上传的文件格式，10001 岛津 | 10002 沃特斯毛发案件 | 20002 沃特斯任务 | 20001 沃特斯毛发任务", required = true),
            @ApiImplicitParam(name = "testId", value = "实验id", required = true)
    })
    public R parseTestData(@RequestPart("file") MultipartFile file,
                           @RequestParam("fileTypeCode") String fileTypeCode,
                           @RequestParam("testId") String testId) {
        try {
            testRecordSampleDataService.validateTestStatus(testId);
            // 先删除这个实验id有关的数据在插入下新数据
            testRecordSampleDataService.delete(testId);
            switch (BusinessType.getBusinessTypeByType(fileTypeCode)) {
                case SCREENING_EVENT:
                case NPS_CASE: {
                    List<NPSDataFileStruct> retDataList = TestDataFileUtil.analysisNpsDataFile(file);//NPS文件解析
                    Boolean saveTestDataFromNps = testRecordSampleDataService.saveTestDataFromNps(retDataList, testId);
                    return saveTestDataFromNps ? R.ok(true, "上传数据成功") : R.failed(false, "上传数据失败!");
                }
                case BOINT_CASE: {
                    Map<String, List<HairSewageCompoundData>> hairCompoundDataMap = TestDataFileUtil.analysisWtsDataFile(file, 1);//毛发案件文件解析 /毛发任务文件解析
                    Boolean saveTestDataHairCase = testRecordSampleDataService.saveTestDataHairCase(hairCompoundDataMap, testId);
                    return saveTestDataHairCase ? R.ok(true, "上传数据成功") : R.failed(false, "上传数据失败!");
                }
                case SEWAGE_JOB: {
                    // /污水任务文件解析
                    Map<String, List<HairSewageCompoundData>> sewageCompoundDataMap = TestDataFileUtil.analysisWtsDataFile(file, 2);//毛发案件文件解析 /毛发任务文件解析
                    Boolean saveTestDataHairCase = testRecordSampleDataService.saveTestDataHairSewageTask(sewageCompoundDataMap, testId, fileTypeCode);
                    return saveTestDataHairCase ? R.ok(true, "上传数据成功") : R.failed(false, "上传数据失败!");
                }
                case BOINT_JOB: {
                    // /毛发任务文件解析
                    Map<String, List<HairSewageCompoundData>> hairCompoundDataMap = TestDataFileUtil.analysisWtsDataFile(file, 1);//毛发案件文件解析 /毛发任务文件解析
                    Boolean saveTestDataHairCase = testRecordSampleDataService.saveTestDataHairSewageTask(hairCompoundDataMap, testId, fileTypeCode);
                    return saveTestDataHairCase ? R.ok(true, "上传数据成功") : R.failed(false, "上传数据失败!");
                }
            }
        } catch (Exception err) {
            err.printStackTrace();
            if (err instanceof RuntimeException) {
                return R.failed(err.getMessage());
            }
            return R.failed("上传文件异常，请检查数据文件");
        }
        return R.failed("上传文件异常，请检查数据文件");
    }

    //手动录入结果的保存  -nps
    @PostMapping("/saveNpsManualData")
    @ApiOperation(value = "保存手动录入的实验结果数据", notes = "保存手动录入的实验结果数据")
    private R saveNpsManualData(@RequestBody List<NPSDataFileStruct> npsDataFileStruct, String testId) {
        return R.ok(testRecordSampleDataService.saveTestDataFromNps(npsDataFileStruct, testId));
    }

    @PutMapping("/saveQuantitativeResults")
    @ApiOperation(value = "保存实验数据的定量结果", notes = "保存实验数据的定量结果")
    private R saveQuantitativeResults(@RequestBody SaveQuantitativeResultsDTO dto) {
        boolean success = false;
        try {
            success = testRecordSampleDataService.saveQuantitativeResults(dto);
        } catch (Exception e) {
            e.printStackTrace();
            if (e instanceof TooManyResultsException) {
                return R.failed(String.format("在上样编号 %s 中检测化合物 %s 在不同的实验中出现重复！", dto.getSampleName(), dto.getCompoundName()));
            } else if (e instanceof RuntimeException) {
                return R.failed(e.getMessage());
            }
            return R.failed("系统出错，请联系管理员！");
        }
        return R.ok(success);
    }

    @DeleteMapping("/deleteQuantitativeResults")
    @ApiOperation(value = "删除实验数据的定量结果", notes = "删除实验数据的定量结果, 这里的删除只是把定量结果制空")
    private R deleteQuantitativeResults(@RequestParam("testSampleDataId") String testSampleDataId) {
        boolean deleted = false;
        try {
            deleted = testRecordSampleDataService.deleteQuantitativeResults(testSampleDataId);
        } catch (Exception e) {
            e.printStackTrace();
            if (e instanceof RuntimeException) {
                return R.failed("删除失败！" + e.getMessage());
            }
            return R.failed("删除失败！");
        }
        return R.ok(deleted);
    }

    @DlpAccessLimit(seconds = 60) // 设置该接口60秒内只能请求5次
    @PutMapping("/updateEntrustTestData")
    @ApiOperation(value = "修改导入的实验数据", notes = "修改导入的实验数据")
    public R updateEntrustTestData(@RequestBody List<SampleInspectDataDTO> dtoList) {
        if (CollUtil.isEmpty(dtoList)) {
            return R.failed("参数列表不能为空！");
        }
        try {
            testRecordSampleDataService.validateTestStatus(dtoList.get(0).getTestId());
            boolean success = testRecordSampleDataService.updateEntrustTestData(dtoList);
            return success ? R.ok("实验数据保存成功") : R.failed("实验数据保存失败");
        } catch (Exception e) {
            e.printStackTrace();
            return R.failed("实验数据保存失败！" + e.getMessage());
        }
    }

    //分析获取检验结果
    @GetMapping("/getAnalysisTestResult")
    @ApiOperation(value = "获取实验结果", notes = "获取实验结果, 其中 " +
            "targetRtTime 目标物保留时间，" +
            "stdRtTime 标准物保留时间，" +
            "rtTimeError 保留时间相对误差，" +
            "rtTimeWithinError 保留时间是否在误差范围内")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "testId", value = "实验id", required = true),
            @ApiImplicitParam(name = "type", value = "检验数据的类型，比如说是nps的还是毛发案件的", required = true)
    })
    public R getAnalysisTestResult(@RequestParam("testId") String testId, @RequestParam("type") String type) {
        if (type.equals(BusinessType.BOINT_CASE.getBusinessType())
                || type.equals(BusinessType.NPS_CASE.getBusinessType())
                || type.equals(BusinessType.SCREENING_EVENT.getBusinessType())) {
            return R.ok(testRecordSampleDataService.getSampleTestDataByTestId(testId, type));
        } else {
            // 任务实验数据
            Map<String, JSONArray> map = testRecordSampleDataService.queryTaskTestResult(testId);
            return R.ok(map);
        }
    }

    @PostMapping("/getAnalysisTestResultPage")
    @ApiOperation(value = "分页查询-获取实验结果", notes = "分页查询-获取实验结果")
    public R<IPage<TestRecordSampleDataVO>> getAnalysisTestResultPage(@RequestBody @Valid AnalysisTestResultPageQuery query) {
        IPage<TestRecordSampleDataVO> page = null;
        try {
            page = testRecordSampleDataService.getSampleTestDataByTestIdPage(query);
        } catch (Exception e) {
            e.printStackTrace();
            return R.failed("查询失败，系统异常！");
        }
        return R.ok(page);
    }

    @GetMapping("/getSampleTestDataByBusinessId")
    @ApiOperation(value = "根据业务id查询检验数据, 这里的业务id可能是委托id 、 筛查id、 任务id", notes = "根据业务id查询检验数据, 这里的业务id可能是委托id 、 筛查id、 任务id")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "businessId", value = "业务id", required = true),
            @ApiImplicitParam(name = "type", value = "查询的业务类型， 10000 委托 | 20000 任务 | 30000 筛查", required = false)
    })
    public R getSampleTestDataByBusiness(@RequestParam("businessId") String businessId, Integer type) {
        List<?> sampleTestDataByBusiness = null;
        try {
            if (type != null && type.equals(20000)) {
                // 20000 代表该业务id是任务的
                Map<String, JSONArray> map = testRecordSampleDataService.queryTaskTestResultByBusiness(businessId);
                return R.ok(map);
            }
            sampleTestDataByBusiness = testRecordSampleDataService.getSampleTestDataByBusiness(businessId);
        } catch (Exception e) {
            e.printStackTrace();
            if (e.getMessage().contains("Duplicate key")) {
                return R.failed("查询失败，系统异常，数据中在同一个化合物中有重复编号存在！");
            } else if (e instanceof RuntimeException) {
                return R.failed("查询失败，系统异常！" + e.getMessage());
            }
            return R.failed("查询失败，系统异常！");
        }
        return R.ok(sampleTestDataByBusiness);
    }

    // 实验结果等相关接口
    @PostMapping("/queryTestResultPage")
    @ApiOperation(value = "实验结果查询中分页查询", notes = "实验结果查询中分页查询, 10000 委托、20000 任务、 30000 筛查")
    public R<IPage<TestResultBusinessVO>> queryTestResultPage(@RequestBody QueryTestResultPageQuery dto, HttpServletRequest theHttpServletRequest) {
        Principal principal = theHttpServletRequest.getUserPrincipal();
        DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal();
        IPage<TestResultBusinessVO> resultPage = null;
        try {
            resultPage = testRecordSampleDataService.queryTestResultPage(
                    new Page<TestResultBusinessVO>(dto.getCurrent(), dto.getSize()),
                    dto, dlpUser);
        } catch (Exception e) {
            e.printStackTrace();
            return R.failed("分页查询出错，详细信息请查看控制台！");
        }

        return R.ok(resultPage);
    }

    @PostMapping("/finishTest")
    @ApiOperation(value = "完成实验", notes = "完成实验")
    @ApiImplicitParam(name = "testId", value = "实验id", required = true)
    public R finishTest(@RequestParam("testId") String testId) {
//        testRecordSampleDataService.finishTest(testId);
        try {
            return testRecordSampleDataService.finishTest(testId);
        } catch (Exception e) {
            e.printStackTrace();
            return R.failed(e.getMessage());
        }
    }

    @PostMapping("/queryWaitApproveTaskTestDataPage")
    @ApiOperation(value = "分页查询-获取审核的任务检验数据", notes = "分页查询-获取审核的任务检验数据")
    public R queryWaitApproveTaskTestDataPage(@RequestBody @Valid TaskTestDataPageDTO pageDTO) {
        Map<String, Object> map = null;
        try {
            map = testRecordSampleDataService.queryWaitApproveTaskTestDataPage(pageDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return R.failed("查询失败，系统异常！");
        }
        return R.ok(map);
    }

    @PutMapping("/audit")
    @ApiOperation(value = "审核审批数据", notes = "审核审批数据")
    public R audit(@RequestBody @Valid AuditDataDTO auditDataDTO, HttpServletRequest httpServletRequest) {
        return testRecordSampleDataService.auditTaskTestData(auditDataDTO, httpServletRequest);
    }


    @PutMapping("/updateCompoundCnName")
    @ApiOperation(value = "添加中文化合物名称", notes = "添加中文化合物名称")
    public R updateCompoundCnName(@RequestBody UpdateCompoundCnNameDto dto) {
        List<TestRecordSampleData> list = testRecordSampleDataService.list(Wrappers.<TestRecordSampleData>lambdaQuery()
                .in(TestRecordSampleData::getId, dto.getIdList()));

        list.forEach(testRecordSampleData -> {
            testRecordSampleData.setCompoundCnName(dto.getCompoundCnName());
            testRecordSampleDataService.updateById(testRecordSampleData);
        });
        return R.ok("更新成功!");
    }


}
