package com.lantone.daqe.facade;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lantone.common.api.CommonResult;
import com.lantone.common.enums.IsDeleteEnum;
import com.lantone.common.exception.Asserts;
import com.lantone.common.util.BeanUtil;
import com.lantone.common.util.DateUtil;
import com.lantone.common.util.ListUtil;
import com.lantone.common.util.StringUtil;
import com.lantone.common.util.SysUserUtils;
import com.lantone.daqe.dto.ExportImportOperationDTO;
import com.lantone.daqe.dto.GetMatchingOperationPageDTO;
import com.lantone.daqe.dto.GetOperationByIdDTO;
import com.lantone.daqe.dto.GetOperationPageDTO;
import com.lantone.daqe.entity.OperationInfo;
import com.lantone.daqe.facade.base.OperationInfoFacade;
import com.lantone.daqe.service.impl.OperationInfoServiceImpl;
import com.lantone.daqe.util.ExcelUtils;
import com.lantone.daqe.vo.AddOperationVO;
import com.lantone.daqe.vo.DelOperationByIdVO;
import com.lantone.daqe.vo.GetMatchingOperationVO;
import com.lantone.daqe.vo.GetOperationByIdVO;
import com.lantone.daqe.vo.GetOperationPageVO;
import com.lantone.daqe.vo.ImportOperationVO;
import com.lantone.daqe.vo.MatchingOperationVO;
import com.lantone.daqe.vo.UpOperationByIdVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * @Description: 手术管理-业务处理类
 * @author: rengb
 * @time: 2021/7/20 12:39
 */
@Component
public class OperationManagementFacade {

    @Autowired
    private OperationInfoFacade operationInfoFacade;

    @Autowired
    private OperationInfoServiceImpl operationInfoServiceImpl;
    //医院手术/操作名称长度
    private int operationLength = 30;
    //手术代码
    private int codeLength = 30;

    public IPage<GetOperationPageDTO> getOperationPage(GetOperationPageVO getOperationPageVO) {
        Page<GetOperationPageDTO> getOperationPageDTOPage = new Page<>();

        QueryWrapper<OperationInfo> operationInfoQueryWrapper = new QueryWrapper<>();
        operationInfoQueryWrapper.eq(getOperationPageVO.getHospitalId() != null, "hospital_id", getOperationPageVO.getHospitalId());
        operationInfoQueryWrapper.like(StringUtil.isNotBlank(getOperationPageVO.getCode()), "code", getOperationPageVO.getCode());
        operationInfoQueryWrapper.like(StringUtil.isNotBlank(getOperationPageVO.getName()), "name", getOperationPageVO.getName());
        operationInfoQueryWrapper.like(StringUtil.isNotBlank(getOperationPageVO.getStandard()), "standard", getOperationPageVO.getStandard());
        if (StringUtil.isNotBlank(getOperationPageVO.getIsMapping())) {
            if (getOperationPageVO.getIsMapping().equals("0")) {
                operationInfoQueryWrapper.isNull("standard");
            } else if (getOperationPageVO.getIsMapping().equals("1")) {
                operationInfoQueryWrapper.isNotNull("standard");
            }
        }
        Page<OperationInfo> operationInfoPage = new Page<>(getOperationPageVO.getCurrent(), getOperationPageVO.getSize());
        operationInfoFacade.page(operationInfoPage, operationInfoQueryWrapper);
        BeanUtil.copyProperties(operationInfoPage, getOperationPageDTOPage);
        List<GetOperationPageDTO> getOperationPageDTOList = BeanUtil.listCopyTo(operationInfoPage.getRecords(), GetOperationPageDTO.class);
        getOperationPageDTOList.forEach(i -> {
            i.setIsMapping(StringUtil.isBlank(i.getStandard()) ? "未匹配" : "已匹配");
        });

        getOperationPageDTOPage.setRecords(getOperationPageDTOList);
        return getOperationPageDTOPage;
    }

    /**
     * 新增手术 业务处理
     *
     * @param addOperationVO
     * @return 是否新增成功
     */
    public boolean addOperation(AddOperationVO addOperationVO) {
        OperationInfo operationInfo = new OperationInfo();
        BeanUtil.copyProperties(addOperationVO, operationInfo);
        operationInfoFacade.assertIsExist(operationInfo);
        String currentUserId = SysUserUtils.getCurrentPrincipleIdStr();
        Date now = DateUtil.now();
        operationInfo.setCreator(currentUserId);
        operationInfo.setGmtCreate(now);
        operationInfo.setModifier(currentUserId);
        operationInfo.setGmtModified(now);
        return operationInfoFacade.save(operationInfo);
    }

    /**
     * 通过id修改手术
     *
     * @param upOperationByIdVO
     * @return 是否修改成功
     */
    public Boolean upOperationById(UpOperationByIdVO upOperationByIdVO) {
        if (operationInfoFacade.getById(upOperationByIdVO.getId()) == null) {
            Asserts.fail("该手术已被删除！");
        }
        OperationInfo operationInfo = new OperationInfo();
        BeanUtil.copyProperties(upOperationByIdVO, operationInfo);
        operationInfoFacade.assertIsExist(operationInfo);
        operationInfo.setModifier(SysUserUtils.getCurrentPrincipleIdStr());
        operationInfo.setGmtModified(DateUtil.now());
        return operationInfoFacade.updateById(operationInfo);
    }

    /**
     * 通过id删除手术
     *
     * @param delOperationByIdVO
     * @return 是否删除成功
     */
    public Boolean delOperationById(DelOperationByIdVO delOperationByIdVO) {
        return operationInfoFacade.removeByIds(delOperationByIdVO.getIds());
    }

    /**
     * 匹配手术信息
     *
     * @param matchingOperationVO
     * @Return java.lang.Boolean
     */
    public Boolean matchingOperation(MatchingOperationVO matchingOperationVO) {
        OperationInfo operationInfo = new OperationInfo();
        BeanUtils.copyProperties(matchingOperationVO, operationInfo);
        operationInfo.setModifier(SysUserUtils.getCurrentPrinciple() == null ? "0" : SysUserUtils.getCurrentPrinciple());
        operationInfo.setGmtModified(DateUtil.now());
        return operationInfoFacade.updateById(operationInfo);
    }

    /**
     * 医院手术标准词匹配信息导入
     *
     * @param response
     * @param file
     * @Return void
     */
    public void importOperation(HttpServletResponse response, MultipartFile file) {

        List<ImportOperationVO> operationExcelVOS = ExcelUtils.importExcel(file, 0, 1, ImportOperationVO.class);
        if (ListUtil.isEmpty(operationExcelVOS)) {
            Asserts.fail("Excel文件为空");
        }
        Long hospitalId = SysUserUtils.getCurrentHospitalId();
        //数据规范校验
        List<ExportImportOperationDTO> errExports = new ArrayList<>();
        if (checkData(operationExcelVOS, errExports, hospitalId)) {
            String fileName = "医院手术标准词匹配信息导入异常.xls";
            ExcelUtils.exportExcelUser(errExports, null, "sheet1", ExportImportOperationDTO.class, fileName, response);
        } else {
            //去重
            List<ImportOperationVO> temp = delRepeat(operationExcelVOS);
            //导入
            List<OperationInfo> insert = BeanUtil.listCopyTo(temp, OperationInfo.class);
            //拼装 医院id、创建时间、更新时间
            insert.stream().forEach(operationInfo -> {
                operationInfo.setHospitalId(hospitalId != null ? hospitalId : 0);
                operationInfo.setGmtCreate(DateUtil.now());
                operationInfo.setCreator(SysUserUtils.getCurrentPrincipleId() != null ? SysUserUtils.getCurrentPrincipleId() + "" : "0");
                operationInfo.setGmtModified(DateUtil.now());
            });

            boolean out = operationInfoServiceImpl.saveBatch(insert);
            CommonResult<String> outMsg = null;
            response.setContentType("text/html;charset=utf-8");
            if (out) {
                outMsg = CommonResult.success(String.format("模板成功导入%s条数据", insert.size()));
                try {
                    response.getWriter().println(JSONObject.toJSONString(outMsg));
                    response.flushBuffer();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                Asserts.fail("数据插入失败");
            }
        }
    }


    /**
     * 数据校验
     *
     * @param importOperationVOS 导入数据
     * @param errExports         导出异常
     * @Return java.lang.Boolean
     */
    private Boolean checkData(List<ImportOperationVO> importOperationVOS, List<ExportImportOperationDTO> errExports, Long hospitalId) {
        AtomicBoolean errorFlog = new AtomicBoolean(false);
        //获取数据库数据 判断医院手术/操作名称和手术和操作代码用于重复校验
        List<OperationInfo> operationInfos = operationInfoFacade.list(new QueryWrapper<OperationInfo>()
                .eq("hospital_id", hospitalId)
                .eq("is_deleted", IsDeleteEnum.N.getKey()));
        List<String> operationNames = operationInfos.stream().map(OperationInfo::getName).collect(Collectors.toList());
        List<String> codes = operationInfos.stream().map(OperationInfo::getCode).collect(Collectors.toList());

        importOperationVOS.stream().forEach(importOperationVO -> {
            ExportImportOperationDTO exportImportOperationDTO = new ExportImportOperationDTO();
            BeanUtil.copyProperties(importOperationVO, exportImportOperationDTO);
            StringBuffer errMsg = new StringBuffer();
            //数据校验(非空和过长、库中已存在)
            //name
            if (StringUtil.isEmpty(importOperationVO.getName())) {
                errMsg.append("【医院手术/操作名称】未填写").append(";");
                errorFlog.set(true);
            } else if (importOperationVO.getName().length() > operationLength) {
                errMsg.append("【医院手术/操作名称】过长").append(";");
                errorFlog.set(true);
            } else if (operationNames.contains(importOperationVO.getName())) {
                errMsg.append("【医院手术/操作名称】已存在，无法重复导入").append(";");
                errorFlog.set(true);
            }

            //code
            if (StringUtil.isNotEmpty(importOperationVO.getCode())) {
                if (importOperationVO.getCode().length() > codeLength) {
                    errMsg.append("【手术/操作代码】过长").append(";");
                    errorFlog.set(true);
                } else if (codes.contains(importOperationVO.getCode())) {
                    errMsg.append("【手术/操作代码】已存在，无法重复导入").append(";");
                    errorFlog.set(true);
                }
            }

            exportImportOperationDTO.setErrMsg(errMsg.toString());
            errExports.add(exportImportOperationDTO);
        });
        return errorFlog.get();
    }

    /**
     * 去重
     *
     * @param importOperationVOS
     * @Return java.util.List<com.lantone.daqe.vo.ImportOperationVO>
     */
    private List<ImportOperationVO> delRepeat(List<ImportOperationVO> importOperationVOS) {

        //通过标准词去重
        LinkedHashMap<String, ImportOperationVO> tempMap = importOperationVOS.stream()
                .collect(Collectors.toMap(ImportOperationVO::getName, ImportOperationVO -> ImportOperationVO, (k1, k2) -> k1, LinkedHashMap::new));
        return tempMap.values().stream().collect(Collectors.toList());
    }

    /**
     * 获取手术匹配信息分页列表
     *
     * @param getMatchingOperationVO
     * @Return com.baomidou.mybatisplus.core.metadata.IPage<com.lantone.daqe.dto.GetMatchingOperationPageDTO>
     */
    public IPage<GetMatchingOperationPageDTO> getMatchingOperationPage(GetMatchingOperationVO getMatchingOperationVO) {

        return operationInfoFacade.getBaseMapper().getMatchingOperationPage(getMatchingOperationVO);
    }

    /**
     * 手术匹配信息查看
     *
     * @param getOperationByIdVO
     * @Return com.lantone.daqe.dto.GetOperationByIdDTO
     */
    public GetOperationByIdDTO getOperationById(GetOperationByIdVO getOperationByIdVO) {
        GetOperationByIdDTO out = new GetOperationByIdDTO();
        BeanUtils.copyProperties(operationInfoFacade.getById(getOperationByIdVO.getId()), out);
        out.setIsMapping(StringUtil.isBlank(out.getStandard()) ? "未匹配" : "已匹配");
        return out;
    }
}