package digital.laboratory.platform.imr.controller;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import digital.laboratory.platform.common.core.util.R;
import digital.laboratory.platform.common.feign.RemoteWord2PDFService;
import digital.laboratory.platform.common.log.annotation.SysLog;
import digital.laboratory.platform.common.mybatis.security.service.DLPUser;
import digital.laboratory.platform.common.oss.service.OssFile;
import digital.laboratory.platform.imr.dto.*;
import digital.laboratory.platform.imr.entity.*;
import digital.laboratory.platform.imr.enums.OutboundType;
import digital.laboratory.platform.imr.mapper.DestructionDetailMapper;
import digital.laboratory.platform.imr.mapper.SampleOutWarehouseApplyMapper;
import digital.laboratory.platform.imr.mapper.SampleOutboundRecordMapper;
import digital.laboratory.platform.imr.mapper.SampleStorageMapper;
import digital.laboratory.platform.imr.service.DestructionPublicityService;
import digital.laboratory.platform.imr.service.SampleOutWarehouseApplyService;
import digital.laboratory.platform.imr.service.SampleOutWarehouseService;
import digital.laboratory.platform.imr.vo.*;
import feign.Response;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.security.Principal;
import java.util.*;

/**
 * 自定义出库controller
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/sample_out_Warehouse" )
@Api(value = "sample_out_Warehouse", tags = "样本出库管理")
public class SampleOutWarehouseController {



    private final SampleOutWarehouseApplyService sampleOutWarehouseApplyService;

    private final DestructionPublicityService destructionPublicityService;

    private final DestructionDetailMapper destructionDetailMapper;


    private final SampleOutWarehouseApplyMapper outWarehouseApplyMapper;


    private final SampleOutWarehouseService warehouseService;


    private final SampleStorageMapper storageMapper;


    private final SampleOutboundRecordMapper outboundRecordMapper;


    private final RemoteWord2PDFService remoteWord2PDFService;

    private final OssFile ossFile;




    /**
     * 分页查询
     * @param dto 查询参数管理员可以看见所有数据
     * @return
     */
    @ApiOperation(value = "出库模块领用出库申请--分页查询", notes = "出库模块领用出库申请--分页查询")
    @GetMapping("/page" )
    @PreAuthorize("@pms.hasPermission('imr_inbound_or_outbound_get')" )
    public R<IPage<SampleOutWarehouseApplyVO>> getSampleOutWarehouseApplyPage(QueryDTO dto, HttpServletRequest theHttpServletRequest) {
        Principal principal = theHttpServletRequest.getUserPrincipal();
        DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal();

        QueryWrapper<SampleOutWarehouseApply> query = Wrappers.<SampleOutWarehouseApply>query();
        query.between(dto.getBeginDate()!=null && dto.getFinishDate()!=null,"application_date",dto.getBeginDate(),dto.getFinishDate());
        query.orderByDesc("create_time");

        if (dto.getStatus()==0){//返回待审核和待使用的数据
            ArrayList<Integer> integers = new ArrayList<>();
            integers.add(1);
            integers.add(2);
            integers.add(3);
            query.in("status",integers);
        }else if (dto.getStatus()==1){
            query.eq("status",1);
        }
        else if (dto.getStatus()==2){
            query.eq("status",2);
        }
        else if (dto.getStatus()==3){
            query.eq("status",3);
        }

        Page<SampleOutWarehouseApply> page = new Page<>(dto.getCurrent(),dto.getSize());

        IPage<SampleOutWarehouseApplyVO> thisPage = sampleOutWarehouseApplyService.getSampleOutWarehouseApplyVOPage(page,query);
        return R.ok(thisPage,"查询出库申请成功");
    }








    /**
     * 检材管理员看见领用出库申请然后点击同意出库
     */

    @ApiOperation(value = "检材管理员--确认同意领用申请", notes = "检材管理员--确认同意领用申请")
    @PutMapping("/reconfirmApply" )
    @PreAuthorize("@pms.hasPermission('imr_inbound_or_outbound_edit')" )
    public R reconfirmApply(String id, HttpServletRequest theHttpServletRequest) {
        Principal principal = theHttpServletRequest.getUserPrincipal();
        DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal();

        if (id.isEmpty()){
            throw new RuntimeException(String.format("id不能为空"));
        }

        SampleOutWarehouseApplyVO applyVO = sampleOutWarehouseApplyService.reconfirmApply(id,dlpUser.getId());


        return R.ok(applyVO,"确认成功");
    }


    /**
     * 根据"取检码"查询相关信息
     */
    @ApiOperation(value = "根据取检码查询相关信息", notes = "根据取检码查询相关信息")
    @SysLog("根据取检码查询相关信息" )
    @GetMapping("/code/{code}" )
    @PreAuthorize("@pms.hasPermission('imr_inbound_or_outbound_get')")
    public R<SampleOutWarehouseApplyVO> getInfoByCode(@PathVariable("code" ) String code, HttpServletRequest theHttpServletRequest) {

        if ("".equals(code)||code.isEmpty()) {
            throw new RuntimeException(String.format("取检码不能为空"));
        }
        SampleOutWarehouseApplyVO vo =  sampleOutWarehouseApplyService.getInfoByCode(code);
        if (vo!=null) {
            return R.ok(vo,"查询成功");
        }else {
            return R.failed("查询失败");
        }
    }


    /**
     * 根据"取检码"验证出库信息(确认出库)
     * Confirm Outbound
     */

    @ApiOperation(value = "根据取检码验证出库信息(确认出库)", notes = "根据取检码验证出库信息(确认出库)")
    @SysLog("根据取检码验证出库信息(确认出库)" )
    @PutMapping("/confirmOutbound" )
    @PreAuthorize("@pms.hasPermission('imr_inbound_or_outbound_edit')")
    public R<SampleOutWarehouseApplyVO> confirmOutbound(@RequestBody VerificationCode dto, HttpServletRequest theHttpServletRequest) {
        Principal principal = theHttpServletRequest.getUserPrincipal();
        DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal();

        if(dto.getSampleIds().isEmpty()){
            throw new RuntimeException("领用申请样本id不能为空");
        }
        if(StrUtil.isEmpty(dto.getCode())){
            throw new RuntimeException("'取检码不能为空'");
        }

        SampleOutWarehouseApplyVO vo = sampleOutWarehouseApplyService.confirmOutbound(dto,dlpUser);
        return R.ok(vo,"确认出库成功");

    }


    /**
     * 退还/销毁出库---待销毁样本列表查询
     */
    @ApiOperation(value = "待销毁或退还出库的样本查询接口", notes = "待销毁或退还出库的样本查询接口--分页")
    @GetMapping("/toBeDestroyed/page" )
    @PreAuthorize("@pms.hasPermission('imr_inbound_or_outbound_edit')" )
    public R getToBeDestroyedSample(QueryDTO dto) {

        List<String> sampleIds = Arrays.asList(dto.getSampleIds().split(","));
        int size = sampleIds.size();
        if ("".equals(dto.getSampleIds())){
            size = sampleIds.size()-1;
        }


        if(dto.getTotal()!=0){
            int num = 0;//去重后目前能分的页数

            if((dto.getTotal()-size)%8==0){
                num = (dto.getTotal()-size)/8;
            }else {
                num = (dto.getTotal()-size)/8+1;
            }

            System.out.println(num);

            if(dto.getCurrent()>num){
                //求余数
                int a = dto.getTotal()%8;//求最后一页的剩余条数
                if(a==0){
                    a=8;
                    if(sampleIds.size()>=a){
                        dto.setCurrent(num);
                    }
                }else {
                    if(sampleIds.size()>=a){
                        dto.setCurrent(num);
                    }
                }
            }
        }
        Page<SampleStorage> page = new Page<>(dto.getCurrent(),dto.getSize());
        /*
         * 两个条件
         * 审核通过待销毁状态-->=2
         * 销毁申请通过的不能再退还中出现
         *
         * 还在仓库--status==2
         */

        QueryWrapper<SampleStorage> queryWrapper = new QueryWrapper<>();
        queryWrapper.notIn(!sampleIds.isEmpty(),"storage.sample_id",sampleIds);//去重数组sampleIds
        queryWrapper.like(!dto.getName().isEmpty(),"storage.name",dto.getName());
        queryWrapper.eq("storage.status",2);  //只能查找存入仓库的样本数据
        if(dto.getStatus()==null){
            queryWrapper.ne("storage.early_warning",2); //如果是退还出库不需要去查询销毁申请通过的检材
        }else {
            queryWrapper.eq("storage.early_warning",dto.getStatus());//销毁出库就只查询销毁申请通过的
        }
        //queryWrapper.eq(dto.getStatus()!=null,"storage.early_warning",dto.getStatus());
        IPage<BaseSampleVO> sampleVOIPage = storageMapper.getSampleInfoTwo(page,queryWrapper);
        return R.ok(sampleVOIPage,"查询成功");
    }

    /**
     * 退还出库自动查询退还单位
     */
    @ApiOperation(value = "退还出库查询委托方", notes = "退还出库查询委托方")
    @GetMapping("/returnOutboundQuery" )
    @PreAuthorize("@pms.hasPermission('imr_inbound_or_outbound_edit')" )
    public R returnOutboundQuery(String sampleId) {


        String orgName = storageMapper.returnOutboundQuery(sampleId);

        return R.ok(orgName,"查询成功");
    }

    /**
     * 退还出库
     */
    @ApiOperation(value = "退还出库", notes = "退还出库")
    @PutMapping("/returnOutbound" )
    @PreAuthorize("@pms.hasPermission('imr_inbound_or_outbound_edit')" )

    public R returnOutbound(@RequestBody ReturnOutboundDTO dto, HttpServletRequest theHttpServletRequest) {
        Principal principal = theHttpServletRequest.getUserPrincipal();
        DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal();

        if(dto.getSampleIds().isEmpty()){
            throw new RuntimeException("样本信息不能为空");
        }
        if(dto.getReturnInstitution().isEmpty()){
            throw new RuntimeException("退还单位不能为空");
        }

        warehouseService.returnOutbound(dto,dlpUser);

        return R.ok("退还出库成功");

    }

    /**
     * 销毁出库
     */

    @ApiOperation(value = "销毁出库", notes = "销毁出库")
    @PutMapping("/destroyOutbound" )
    @PreAuthorize("@pms.hasPermission('imr_inbound_or_outbound_edit')" )
    public R destroyOutbound(@RequestBody DestroyOutboundDTO dto, HttpServletRequest theHttpServletRequest) {


        Principal principal = theHttpServletRequest.getUserPrincipal();
        DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal();

        /*
         *这里销毁出库可能要先判断是否公示了
         */
//        LambdaQueryWrapper<DestructionDetail> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.in(DestructionDetail::getSampleId, dto.getSampleIds());
//        queryWrapper.orderByDesc(DestructionDetail::getUpdateTime);
//        List<DestructionDetail> destructionDetails = destructionDetailMapper.selectList(queryWrapper); // 查询该dto中的样本id 是否已经公示
//        // 根据公示id 进行分类
//        Map<String, List<DestructionDetail>> collect = destructionDetails.stream().collect(Collectors.groupingBy(item -> item.getDestructionId()));
//        collect.forEach((k, v) -> {
//            // 根据公示详情中关联的公示id 查公示
//            DestructionPublicity oneById = destructionPublicityService.getOneById(k);
//            if (oneById == null || oneById.getStatus() != 1) {
//                // 公示如果查不到或者状态不为1 则提示需要公示
//                throw new RuntimeException("请先进行销毁公示在出口！");
//            }
//        });


        if(dto.getSampleIds().isEmpty()){
            throw new RuntimeException("样本信息不能为空");
        }

        warehouseService.destroyOutbound(dto,dlpUser);

        return R.ok("销毁出库成功");
    }



    /**
     * 入库样本记录分页
     */
    @ApiOperation(value = "出库记录分页", notes = "出库记录分页")
    @GetMapping("/outboundRecord/page" )
    @PreAuthorize("@pms.hasPermission('imr_inbound_or_outbound_get')" )
    public R<IPage<OutboundRecordVO>> outboundRecord(QuerySampleDTO dto) {
        Page<SampleOutboundRecord> page = new Page<>(dto.getCurrent(), dto.getSize());
        IPage<OutboundRecordVO> sampleVOIPage = outboundRecordMapper.outboundRecord(page, Wrappers.<SampleOutboundRecord>query()
                .like(!dto.getName().isEmpty(), "outbound.name", dto.getName())
                .orderByDesc("create_time")
        );

        List<OutboundRecordVO> records = sampleVOIPage.getRecords();
        for (OutboundRecordVO record : records) {
            record.setStatusCode(record.getOutboundType().getStatus());
            if(record.getOutboundType() == OutboundType.RETURN){
                record.setRecipientName(record.getRecipientId());//退还的比较特殊
            }
            //销毁出库
        }
        return R.ok(sampleVOIPage, "查询成功");


    }


        /**
         * 待归还样本toBeReturned
         */
        @ApiOperation(value = "待归还样本--分页", notes = "待归还样本--分页")
        @GetMapping("/toBeReturned/page" )
        @PreAuthorize("@pms.hasPermission('imr_inbound_or_outbound_get')" )
        public R<IPage<ToBeReturnVO>> toBeReturned(QuerySampleDTO dto) {

            Page<SampleStorage> page = new Page<>(dto.getCurrent(), dto.getSize());

            IPage<ToBeReturnVO> sampleVOIPage = storageMapper.toBeReturned(page, Wrappers.<SampleStorage>query()
                    .like(!dto.getName().isEmpty(), "storage.name", dto.getName())
                    .eq("is_return",1)//只查询需要归还的
                    .eq("storage.status",3)
                    .orderByAsc("storage.update_time")
            );
            List<ToBeReturnVO> records = sampleVOIPage.getRecords();
            for (ToBeReturnVO toBeReturnVO : records) {
                String eventName = "";
                //entrustment/hairJob/sewageJob
                switch (toBeReturnVO.getSource()) {
                    case "entrustment":
                        //委托
                        eventName = storageMapper.getEntrustmentName(toBeReturnVO.getSampleId());
                        break;
                    case "hairJob":
                        //毛发
                        eventName = storageMapper.getHairJobName(toBeReturnVO.getSampleId());
                        break;
                    case "sewageJob":
                        //污水
                        eventName = storageMapper.getSewageJobName(toBeReturnVO.getSampleId());
                        break;
                    case "Event污水":
                    case "Event毛发":
                        //内部录入
                        eventName = storageMapper.getEventName(toBeReturnVO.getSampleId());
                        break;
                    default:
                        //特征分析
                        eventName = storageMapper.getFeatureName(toBeReturnVO.getSampleId());
                        break;
                }
                toBeReturnVO.setEventName(eventName);
            }


            return R.ok(sampleVOIPage, "查询成功");


        }

    /**
     * 查询单个待归还样本
     */

    @ApiOperation(value = "待归还样本--详情", notes = "待归还样本--详情")
    @GetMapping("/toBeReturned/detail" )
    @PreAuthorize("@pms.hasPermission('imr_inbound_or_outbound_get')" )
    public R<RecipientDTO> toBeReturnedDetail(String sampleId) {
        
        

        RecipientDTO sampleVOIPage = storageMapper.toBeReturnedDetail(sampleId);

        return R.ok(sampleVOIPage, "查询成功");


    }

    /**
     * 出库模块对应角标
     */

    @ApiOperation(value = "出库模块对应角标0.待确认出库申请;2.出库待归还", notes = "出库模块对应角标0.待确认出库申请;2.出库待归还")
    @GetMapping("/inboundIcon/count" )
    //@PreAuthorize("@pms.hasPermission('imr_inbound_or_outbound_edit')" )
    public R<List<IconDTO>> getIconCount() {


        //出库申请
        QueryWrapper<SampleOutWarehouseApply> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("status",1);//待确认(出库申请带确认)

        Long count = outWarehouseApplyMapper.selectCount(queryWrapper);

        IconDTO destroyed = new IconDTO(count, 0, "destroyed");

        //出库待归还

        QueryWrapper<SampleStorage> wrapper = new QueryWrapper<>();
        wrapper.eq("is_return",1);//需要归还
        wrapper.eq("status",3);//领用出库了

        Long selectCount = storageMapper.selectCount(wrapper);

        IconDTO aReturn = new IconDTO(selectCount, 2, "return");


        ArrayList<IconDTO> iconDTOS = new ArrayList<>();
        iconDTOS.add(destroyed);
        iconDTOS.add(aReturn);
        return R.ok(iconDTOS,"查询成功");

    }



    /**-------出库清单*/
    /**
     * 出库清单
     *
     * @param ids
     *
     * @return
     */
    @ApiOperation(value = "出库清单", notes = "出库清单")
    @SysLog("出库清单")
    @PostMapping("/print/inventory")
//	@PreAuthorize("@pms.hasPermission('EntrustmentEdit')")
    public void bizGetPDFInventory(@RequestBody List<String> ids, HttpServletRequest theHttpServletRequest, HttpServletResponse httpServletResponse) {
        System.out.println("bizApplyWord.................");
        Principal principal = theHttpServletRequest.getUserPrincipal();
        DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal();


        //查询数据
        List<InventorySample> voList = storageMapper.getSampleInventory(new QueryWrapper<SampleStorage>()
                .in("storage.id", ids)//查询该集合中相关样本数据
        );

        if (voList.isEmpty()) {
            throw new RuntimeException("未查询到相关信息");
        }

        String id = IdWorker.get32UUID().toUpperCase();

        String applyFileName = "检材出库清单-"+id;

        String pdfFilePath = "document" + "/"+"inventory" + "/" + id + "/" + applyFileName + ".pdf";
        try {
            //直接调用pdf方法
            GenerateSampleApplyTablePDF(voList,id,theHttpServletRequest,httpServletResponse);
            ossFile.fileGet(pdfFilePath, httpServletResponse.getOutputStream());
            httpServletResponse.setContentType(applyFileName);
        } catch (Exception e) {
            System.out.printf("minioFile objectExist() Exception. %s%n", e.getLocalizedMessage());
            e.printStackTrace();
        }
    }


    private void GenerateSampleApplyTablePDF(List<InventorySample> voList,String id, HttpServletRequest theHttpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        System.out.println("GenerateSampleApplyTablePDF.................");

        //-----------------------------
        // 生成 word 版本的 鉴定委托书

        String applyFileName = "检材出库清单-"+id;

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ossFile.fileGet("template" + "/" + "检材出库清单模板.docx", bos);

        byte[] templateArray = bos.toByteArray();

        ByteArrayInputStream bis = new ByteArrayInputStream(templateArray);
        bos.close();

        for (int i = 0;i<voList.size();i++) {
            InventorySample inventorySample = voList.get(i);
            inventorySample.setNumber(i+1);
        }


        LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();

        Configure config = Configure.builder().
                bind("voList", policy).build();
        /**
         * 循环表格
         */
        XWPFTemplate template = XWPFTemplate.compile(bis, config).render(
                new HashMap<String, Object>() {{
                    put("voList", voList);
                }}
        );
        bis.close();

        ByteArrayOutputStream fosWord = new ByteArrayOutputStream();
        template.write(fosWord);
        template.close();

        //------------
        ByteArrayInputStream fisWord = new ByteArrayInputStream(fosWord.toByteArray());
        fosWord.close();

        //MockMultipartFile mockMultipartFile = new MockMultipartFile("file", entrustmentLetterFileName + ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", fisWord);
        MockMultipartFile mockMultipartFile = new MockMultipartFile("file", applyFileName + ".docx", "image/jpg", fisWord);
        Response response = remoteWord2PDFService.word2pdf(mockMultipartFile);
        fisWord.close();


        ByteArrayOutputStream outPDF = new ByteArrayOutputStream();
        IoUtil.copy(response.body().asInputStream(), outPDF, IoUtil.DEFAULT_MIDDLE_BUFFER_SIZE);
        ByteArrayInputStream isPDF = new ByteArrayInputStream(outPDF.toByteArray());
        outPDF.close();


        ossFile.fileSave("document" + "/" + "inventory" + "/" + id + "/" + applyFileName + ".pdf", isPDF);
        isPDF.close();


        System.out.println("转换为 PDF 结束");

    }




    /**
     * 催还
         */

}
