package com.kcim.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.result.ExcelVerifyHandlerResult;
import cn.afterturn.easypoi.handler.inter.IExcelVerifyHandler;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kcim.common.constants.NumberConstant;
import com.kcim.common.enums.DateStyleEnum;
import com.kcim.common.exception.CostException;
import com.kcim.common.util.*;
import com.kcim.common.util.excel.ExcelStyleUtil;
import com.kcim.common.util.excel.entity.PatientInfoImportEntity;
import com.kcim.dao.model.CostIncomeFile;
import com.kcim.dao.model.ImportPatientInfo;
import com.kcim.dao.repository.DiseaseTypeDiagMapRepository;
import com.kcim.dao.repository.ImportPatientInfoRepository;
import com.kcim.service.CostIncomeFileService;
import com.kcim.service.PatientInfoImportService;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @program: CostAccount
 * @description: 患者信息导入接口实现类
 * @author: Wang.YS
 * @create: 2023-10-19 18:09
 **/
@Service("PatientInfoImportService")
@AllArgsConstructor
@Slf4j
public class PatientInfoImportServiceImpl implements PatientInfoImportService {
    ImportPatientInfoRepository repository;

    DiseaseTypeDiagMapRepository diagMapRepository;

    CostIncomeGroupServiceImpl costIncomeGroupService;

    CostIncomeFileService costIncomeFileService;

    /**
     * 月度信息采集-患者信息导入-获取导入列表
     *
     * @param current        当前页
     * @param pageSize       页容量
     * @param computeDate    核算年月
     * @param departmentName 科室名称
     * @param patientName    患者姓名
     * @param filter
     * @param departmentCode
     * @return 导入列表
     */
    @Override
    public Object getPatientInfoList(Integer current, Integer pageSize, String computeDate, String departmentName, String patientName, String filter, String departmentCode) {
        Page<ImportPatientInfo> page = repository.getPage(current, pageSize, computeDate, departmentName, patientName,filter,departmentCode);
        List<ImportPatientInfo> records = page.getRecords();
        if(!CollectionUtils.isEmpty(records)){
//            for (ImportPatientInfo record : records) {
//                Integer bedDays = calculateBedDays(record.getInHospitalTime(), record.getOutHospitalTime());
//                Integer bedDays1 = calculateCurrentBedDays(record.getInHospitalTime(), record.getOutHospitalTime(), computeDate);
//                System.out.println("visitNo:"+record.getVisitNo()+"床日数："+bedDays+"|当前床日数："+bedDays1);
//            }


            return new PageUtils(records, Math.toIntExact(page.getTotal()),pageSize,current);
        }
        return new PageUtils(new ArrayList<>(), NumberConstant.ZERO,pageSize,current);
    }

    /**
     * 月度信息采集-患者信息导入-获取导出模版
     *
     * @param response 出参
     * @return 导出模版
     */
    @Override
    @SneakyThrows
    public Object exportPatientInfo(HttpServletResponse response) {
        try {

            //配置excel 文件信息
            ExportParams params = new ExportParams();

            params.setTitle("说明：1、为了保证成功导入，请勿修改模板格式\n" +
                    "      2、住院号/门诊号为患者就诊的唯一标识\n" +
                    "      3、多个次诊断及次手术/操作需用|拼接，样式：次诊断代码1|次诊断代码2\n" +
                    "      4、次诊断代码、次诊断名称、主手术/操作代码、主手术/操作名称、次手术/操作代码、次手术/操作名称、DRG/DIP分组代码、DRG/DIP分组名称、临床路径代码、临床路径名称没有可留空\n" +
                    "      5、门急诊患者出院时间和住院天数可不填");
            //设置导出样式
            params.setStyle(ExcelStyleUtil.class);
            params.setTitleHeight(Short.parseShort("25"));
            params.setHeight((short)10);
//            params.setSecondTitleHeight(Short.parseShort("1"));
//            params.setHeaderHeight(1);
            //设置sheetName
            params.setSheetName("患者信息");
            params.setType(ExcelType.XSSF);
//            params.setHeaderColor();
//            params.setFreezeCol(2);
//            FileOutputStream outputStream = new FileOutputStream("E:\\患者信息导入模版.xlsx");

            Workbook workbook = ExcelExportUtil.exportExcel(params, PatientInfoImportEntity.class,new ArrayList<>());
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/vnd.ms-excel");
            String fileName ="患者信息导入模版";
            response.setHeader("Content-Disposition",  URLEncoder.encode(fileName, "UTF-8"));
            workbook.write(response.getOutputStream());
//            workbook.write(outputStream);
//            outputStream.close();
            workbook.close();
        } catch (FileNotFoundException e) {
            throw new CostException(e.getMessage());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return response.getOutputStream();
    }

    /**
     * 月度信息采集-患者信息导入-导入数据
     *
     * @param computeDate 核算年月
     * @param file        文件
     */
    @SneakyThrows
    @Override
    public void importPatientInfo(String computeDate, MultipartFile file) {
//        try {
            if (ObjectUtils.isEmpty(file) || file.getSize() == 0){
                throw new CostException("未获取到导入的excel文件内容");
            }
            log.info("接收到文件：{}",file.getOriginalFilename());
            // 参数1：文件流
            InputStream stream = file.getInputStream();
            // 参数2：导入类型
            ImportParams params = new ImportParams();
            //校验Excel 去掉空行
            params.setNeedVerify(true);
            IExcelVerifyHandler<PatientInfoImportEntity> handler = val ->{
                if(StringUtils.isEmpty(val.getVisitNo())){
                    return new ExcelVerifyHandlerResult(false,"住院号/门诊号不能为空");
                }
                return new ExcelVerifyHandlerResult(true);
            };
            params.setVerifyHandler(handler);
            // 标题占用多少行
            params.setTitleRows(1);
            // 头部属性占用多少行
            params.setHeadRows(1);
            List<PatientInfoImportEntity> patientInfoImportEntities  = ExcelImportUtil.importExcel(stream, PatientInfoImportEntity.class,params);
            if(!CollectionUtils.isEmpty(patientInfoImportEntities)){
                //获取病种对照
//                Map<String, String> diagDiseaseMap = diagMapRepository.getDiagDiseaseMap();
                List<ImportPatientInfo> saveList = new ArrayList<>();
                ImportPatientInfo importPatientInfo = new ImportPatientInfo();
                importPatientInfo.setHospId(UserContext.getHospId());
                importPatientInfo.setComputeDate(computeDate);
                importPatientInfo.setCreateTime(new Date());
                importPatientInfo.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
                for (PatientInfoImportEntity entity : patientInfoImportEntities) {
                    ImportPatientInfo patientInfo = BeanUtil.convertObj(importPatientInfo, ImportPatientInfo.class);
                    patientInfo.setVisitNo(entity.getVisitNo());
                    patientInfo.setPatientNo(entity.getPatientNo());
                    patientInfo.setName(entity.getName());
                    patientInfo.setDepartmentCode(entity.getDepartmentCode());
                    patientInfo.setDepartmentName(entity.getDepartmentName());
                    patientInfo.setType(entity.getType());
                    patientInfo.setPrimaryDiagCode(entity.getPrimaryDiagCode());
//                    if(!CollectionUtils.isEmpty(diagDiseaseMap)){
//                        if(!StringUtils.isEmpty(patientInfo.getPrimaryDiagCode())){
//                            String diseaseType = diagDiseaseMap.get(patientInfo.getPrimaryDiagCode());
//                            if(!StringUtils.isEmpty(diseaseType)){
//                                patientInfo.setDiseaseTypeCode(diseaseType);
//                            }
//                        }
//                    }
                    patientInfo.setPrimaryDiagName(entity.getPrimaryDiagName());
                    patientInfo.setSecondaryDiagCode(entity.getSecondaryDiagCode());
                    patientInfo.setSecondaryDiagName(entity.getSecondaryDiagName());
                    patientInfo.setPrimaryOperationCode(entity.getPrimaryOperationCode());
                    patientInfo.setPrimaryOperationName(entity.getPrimaryOperationName());
                    patientInfo.setSecondaryOperationCode(entity.getSecondaryOperationCode());
                    patientInfo.setSecondaryOperationName(entity.getSecondaryOperationName());
                    patientInfo.setGroupCode(entity.getGroupCode());
                    patientInfo.setGroupName(entity.getGroupName());
                    patientInfo.setClinicalPathwayCode(entity.getClinicalPathwayCode());
                    patientInfo.setClinicalPathwayName(entity.getClinicalPathwayName());
                    patientInfo.setInHospitalTime(entity.getInHospitalTime());
                    patientInfo.setOutHospitalTime(entity.getOutHospitalTime());
                    patientInfo.setInHospitalDays(entity.getInHospitalDays());
                    patientInfo.setInpatientWardCode(entity.getInpatientWardCode());
                    patientInfo.setInpatientWardName(entity.getInpatientWardName());
                    //添加计算床日数
                    if(patientInfo.getOutHospitalTime() !=null){
                        Integer bedDays = calculateBedDays(patientInfo.getInHospitalTime(), patientInfo.getOutHospitalTime());
                        patientInfo.setBedDays(bedDays);
                    }
                    Integer currentBedDays = calculateCurrentBedDays(patientInfo.getInHospitalTime(), patientInfo.getOutHospitalTime(), computeDate);
                    patientInfo.setCurrentBedDays(currentBedDays);
                    saveList.add(patientInfo);
                }
                // 文件上传
                String uploadFile = costIncomeGroupService.uploadFile(file);
                // 上传记录保存
                if (StrUtil.isBlank(uploadFile)) {
                    throw new CostException(500, "文件上传异常");
                }
                CostIncomeFile costIncomeFile = costIncomeFileService.saveFile(saveList.size(), file, UserContext.getHospId(), new ArrayList<>(), uploadFile, NumberConstant.FIVE, ComputeDateUtils.getComputeYear(computeDate), ComputeDateUtils.getComputeMonth(computeDate));
                Long id = costIncomeFile.getId();

                if(!CollectionUtils.isEmpty(saveList)){
//                    check(computeDate);
                    saveList.forEach(f->f.setFileId(id));
                    repository.saveBatch(saveList,50);
                }

//                if(!CollectionUtils.isEmpty(saveList)){
//                    check(computeDate);
//                    repository.saveBatch(saveList,50);
//                }

            }

//        }catch (Exception e){
//            throw new RuntimeException(e);
//        }
    }

    @Override
    public Object getPatientInfoDepartment(Integer type, String filter, String computeDate) {
        return repository.getPatientInfoDepartment(type,filter,computeDate);

    }

    @Override
    public void removePatientInfo(String computeDate) {
        check(computeDate);
    }

    /**
     * 按文件id移除记录
     * @param computeDate
     * @param fileId
     */
    @Override
    public void removePatientInfoByFileId(String computeDate, Long fileId) {
        repository.removePatientInfoByFileId(computeDate,fileId);

    }

    /**
     * 按文件id还原记录
     * @param computeDate
     * @param fileId
     */
    @Override
    public void reducingPatientInfoByFileId(String computeDate, Long fileId) {
        repository.reducingPatientInfoByFileId(computeDate,fileId);

    }

    private void check(String computeDate) {
        List<ImportPatientInfo> byComputeDate = repository.getByComputeDate(computeDate);
        if(!CollectionUtils.isEmpty(byComputeDate)){
            for (ImportPatientInfo patientInfo : byComputeDate) {
                patientInfo.setDeleteTime(new Date());
                patientInfo.setDeleteUser(String.valueOf(UserContext.getCurrentUser().getId()));
            }
            repository.updateBatchById(byComputeDate);
            List<Integer> collect = byComputeDate.stream().map(ImportPatientInfo::getId).collect(Collectors.toList());
            repository.removeBatchByIds(collect);
        }
    }

    private Integer calculateBedDays(Date inHospitalDate,Date outHospitalDate){
        int intervalDays = DateUtils.getIntervalDays(inHospitalDate, outHospitalDate);
        if(intervalDays == NumberConstant.ZERO){
            intervalDays = NumberConstant.ONE;
        }
        return intervalDays;

    }

    private Integer calculateCurrentBedDays(Date inHospitalDate,Date outHospitalDate,String computeDate){
//        入院日期=实际入院日期>当月最小日期？实际入院日期：当月最小日期
//        出院日期=实际出院日期>当月最大日期？当月最大日期：实际出院日期
//        床日数=出院日期-入院日期，如果是当日入出院算1天(算出来的床日数为0时算1天)
//        实际出院日期>当月最大日期或没有出院日期时，床日数需+1
        Date date = DateUtils.StringToDate(computeDate, DateStyleEnum.YYYY_MM);
        Date firstDateOfMonth = DateUtils.getFirstDateOfMonth(date);
        Date lastDateOfMonth = DateUtils.getLastDateOfMonth(date);
        Date currentOutHospitalDate ;
        int currentBedDays ;
        Date currentInHospitalDate = inHospitalDate.compareTo(firstDateOfMonth) >= 0 ? inHospitalDate : firstDateOfMonth;
        if(outHospitalDate == null){
            currentOutHospitalDate = lastDateOfMonth;
            currentBedDays =  DateUtils.getIntervalDays(currentOutHospitalDate,currentInHospitalDate) + 1;
        }else {
            boolean last = false;
            if(outHospitalDate.compareTo(firstDateOfMonth)>=0){
                if (outHospitalDate.compareTo(lastDateOfMonth) >= 0) {
                    currentOutHospitalDate = lastDateOfMonth;
                    last = true;
                }else {
                    currentOutHospitalDate = outHospitalDate;
                }
                currentBedDays =  DateUtils.getIntervalDays(currentOutHospitalDate,currentInHospitalDate) ;
                if(last){
                    currentBedDays += 1;
                }
            }else {
                //出院日期小于当前核算年月最小日期 按原出入院日期算
                currentBedDays = calculateBedDays(inHospitalDate, outHospitalDate);
            }
        }
        if(currentBedDays==NumberConstant.ZERO){
            currentBedDays = NumberConstant.ONE;
        }
        return currentBedDays;

    }
}
