package cn.hnthyy.thmz.Utils;

import cn.hnthyy.thmz.entity.his.mz.MzyReqrec;
import cn.hnthyy.thmz.entity.his.zd.ZdUnitCode;
import cn.hnthyy.thmz.entity.thmz.Mzmxsr;
import cn.hnthyy.thmz.enums.YesNoEnum;
import cn.hnthyy.thmz.vo.ChargeFeeVo;
import cn.hnthyy.thmz.vo.MzyReqrecVo;
import cn.hnthyy.thmz.vo.ReqrecVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.*;

import static org.apache.poi.ss.usermodel.CellType.*;

/**
 * EXCEl 导入导出工具
 */
@Slf4j
public class ExcelUtil {
    private static final String FILE_NAME_KEY = "fileName";
    private static final String SHEET_NAME = "sheet";
    private static final String HEAD_KEY = "head";
    private static final String DATA_KEY = "data";
    private static final String HEAD_ARR_KEY = "headArr";
    private static final String HEAD_NUM_KEY = "headNum";
    private static final Integer YP_REPORT_COLUMNS_LENGTH = 13;
    private static final Integer VERSION_2007 = 2007;
    private static final Integer VERSION_2003 = 2003;

    /**
     * 将科室字典列表对象转换为导出Excel
     *
     * @param request
     * @param response
     * @param zdUnitCodes
     */
    public static void exportExcelForZdUnitCode(HttpServletRequest request, HttpServletResponse response, List<ZdUnitCode> zdUnitCodes) {
        Map<String, Object> data = fomartZdUnitCode(zdUnitCodes);
        exportExcel(request, response, data, YP_REPORT_COLUMNS_LENGTH,VERSION_2007);
    }


    /**
     * 将收费清单列表对象转换为导出Excel
     *
     * @param request
     * @param response
     * @param chargeFeeVos
     */
    public static void exportExcelForChargeDetail(HttpServletRequest request, HttpServletResponse response, List<ChargeFeeVo> chargeFeeVos) {
        Map<String, Object> data = fomartChargeDetail(chargeFeeVos);
        exportExcel(request, response, data, YP_REPORT_COLUMNS_LENGTH,VERSION_2007);
    }


    /**
     * 将挂号清单列表对象转换为导出Excel
     *
     * @param request
     * @param response
     * @param reqrecVos
     */
    public static void exportExcelForReqrec(HttpServletRequest request, HttpServletResponse response, List<ReqrecVo> reqrecVos) {
        Map<String, Object> data = fomartReqrec(reqrecVos);
        exportExcel(request, response, data, YP_REPORT_COLUMNS_LENGTH,VERSION_2007);
    }


    /**
     * 将门诊收入明细列表对象转换为导出Excel
     *
     * @param request
     * @param response
     * @param thmzmxsrs
     */
    public static void exportExcelForThmzmxsrs(HttpServletRequest request, HttpServletResponse response, List<Mzmxsr> thmzmxsrs) {
        Map<String, Object> data = fomartThmzmxsr(thmzmxsrs);
        exportExcel(request, response, data, YP_REPORT_COLUMNS_LENGTH,VERSION_2007);
    }

    /**
     * 将挂号列表对象转换为导出Excel
     *
     * @param request
     * @param response
     * @param mzyReqrecList
     */
    public static void exportExcelForReqrecList(HttpServletRequest request, HttpServletResponse response, List<MzyReqrecVo> mzyReqrecList) {
        Map<String, Object> data = fomartReqrecList(mzyReqrecList);
        exportExcel(request, response, data, YP_REPORT_COLUMNS_LENGTH,VERSION_2007);
    }



    /**
     * 方法名：exportExcel
     * 功能：导出Excel
     * 描述：
     * 创建人：typ
     * 创建时间：2018/10/19 16:00
     * 修改人：
     * 修改描述：
     * 修改时间：
     */
    public static void exportExcel(HttpServletRequest request, HttpServletResponse response, Map<String, Object> data, Integer columns, Integer version) {
        if (data == null) {
            return;
        }
        log.info("导出解析开始，fileName:{}", data.get(FILE_NAME_KEY));
        try {
            //实例化HSSFWorkbook
            //HSSFWorkbook workbook = new HSSFWorkbook();
            Workbook workbook = null;
            if (version.equals(VERSION_2007)) {
                workbook = new XSSFWorkbook();// 创建 一个excel文档对象
            } else if (version.equals(VERSION_2003)) {
                workbook = new HSSFWorkbook();// 创建 一个excel文档对象
            }
            //创建一个Excel表单，参数为sheet的名字
            Sheet sheet = workbook.createSheet(SHEET_NAME);
            //设置表头
            setTitle(workbook, sheet, (List<Map<String, Object>>) data.get(HEAD_KEY), columns);
            //设置单元格并赋值
            setData(sheet, (List<String[]>) data.get(DATA_KEY), ((List<Map<String, Object>>) data.get(HEAD_KEY)).size());
            //设置浏览器下载
            setBrowser(request, response, workbook, (String) data.get(FILE_NAME_KEY));
            log.info("导出解析成功!");
        } catch (Exception e) {
            log.info("导出解析失败!错误信息{}", e.getMessage());
        }
    }

    /**
     * 方法名：setTitle
     * 功能：设置表头
     * 描述：
     * 创建人：typ
     * 创建时间：2018/10/19 10:20
     * 修改人：
     * 修改描述：
     * 修改时间：
     */
    private static void setTitle(Workbook workbook, Sheet sheet, List<Map<String, Object>> heads, Integer columns) {
        try {
            //设置列宽，setColumnWidth的第二个参数要乘以256，这个参数的单位是1/256个字符宽度
            for (int i = 0; i <= columns; i++) {
                sheet.setColumnWidth(i, 15 * 256);
            }
            //设置为居中加粗,格式化时间格式
            CellStyle style = workbook.createCellStyle();
            Font font = workbook.createFont();
            font.setFontName("宋体");
            font.setFontHeightInPoints((short) 12);// 字体大小
            //font.setBold(true);
            style.setFont(font);
            style.setAlignment(HorizontalAlignment.CENTER);// 左右居中
            style.setVerticalAlignment(VerticalAlignment.CENTER);// 上下居中
            style.setLocked(true);
            style.setDataFormat(HSSFDataFormat.getBuiltinFormat("m/d/yy h:mm"));
            sheet.setColumnWidth((short) 0, (short) 8000);
            for (int i = 0; i < heads.size(); i++) {
                Map<String, Object> head = heads.get(i);
                String[] str = (String[]) head.get(HEAD_ARR_KEY);
                String[] headNum = (String[]) head.get(HEAD_NUM_KEY);
                Row row = sheet.createRow(i);
                row.setHeight((short) 850);
                //创建表头名称
                Cell cell;
                for (int j = 0; j < str.length; j++) {
                    cell = row.createCell(j);
                    cell.setCellValue(str[j]);
                    cell.setCellStyle(style);
                }
                //动态合并单元格
                for (int j = 0; j < headNum.length; j++) {
                    String[] temp = headNum[j].split(",");
                    Integer startRow = Integer.parseInt(temp[0]);
                    Integer overRow = Integer.parseInt(temp[1]);
                    Integer startCol = Integer.parseInt(temp[2]);
                    Integer overCol = Integer.parseInt(temp[3]);
                    if (overRow > startRow || overCol > startCol) {
                        sheet.addMergedRegion(new CellRangeAddress(startRow, overRow,
                                startCol, overCol));
                    }
                }
            }
        } catch (Exception e) {
            log.info("导出时设置表头失败！,错误信息{}", e.getMessage());
        }
    }

    /**
     * 方法名：setData
     * 功能：表格赋值
     * 描述：
     * 创建人：typ
     * 创建时间：2018/10/19 16:11
     * 修改人：
     * 修改描述：
     * 修改时间：
     */
    private static void setData(Sheet sheet, List<String[]> data, Integer rowNum) {
        try {
            for (int i = 0; i < data.size(); i++) {
                Row row = sheet.createRow(rowNum);
                row.setHeight((short) 350);
                for (int j = 0; j < data.get(i).length; j++) {
                    row.createCell(j).setCellValue(data.get(i)[j]);
                }
                rowNum++;
            }
            log.info("表格赋值成功！");
        } catch (Exception e) {
            log.info("表格赋值失败！错误信息{}", e.getMessage());
        }
    }

    /**
     * 方法名：setBrowser
     * 功能：使用浏览器下载
     * 描述：
     * 创建人：typ
     * 创建时间：2018/10/19 16:20
     * 修改人：
     * 修改描述：
     * 修改时间：
     */
    private static void setBrowser(HttpServletRequest request, HttpServletResponse response, Workbook workbook, String fileName) {
        try {
            //清空response
            response.reset();
            fileName = FileUtils.encodeDownloadFilename(fileName, request.getHeader("User-Agent"));
            response.setHeader("contentType", "application/vnd.ms-excel");
            response.setHeader("content-disposition", "attachment;fileName=" + fileName);
            OutputStream os = new BufferedOutputStream(response.getOutputStream());
            //将excel写入到输出流中
            workbook.write(os);
            os.flush();
            os.close();
            log.info("设置浏览器下载成功！");
        } catch (Exception e) {
            log.info("设置浏览器下载失败！错误信息{}", e.getMessage());
        }

    }


    /**
     * 方法名：importExcel
     * 功能：导入
     * 描述：
     * 创建人：typ
     * 创建时间：2018/10/19 11:45
     * 修改人：
     * 修改描述：
     * 修改时间：
     */
    public static List<Object[]> importExcel(String fileName) {
        log.info("导入解析开始，fileName:{}", fileName);
        try {
            List<Object[]> list = new ArrayList<>();
            InputStream inputStream = new FileInputStream(fileName);
            Workbook workbook = WorkbookFactory.create(inputStream);
            Sheet sheet = workbook.getSheetAt(0);
            //获取sheet的行数
            int rows = sheet.getPhysicalNumberOfRows();
            for (int i = 0; i < rows; i++) {
                //过滤表头行
                if (i == 0) {
                    continue;
                }
                //获取当前行的数据
                Row row = sheet.getRow(i);
                Object[] objects = new Object[row.getPhysicalNumberOfCells()];
                int index = 0;
                for (Cell cell : row) {
                    if (cell.getCellType().equals(NUMERIC)) {
                        objects[index] = (int) cell.getNumericCellValue();
                    }
                    if (cell.getCellType().equals(STRING)) {
                        objects[index] = cell.getStringCellValue();
                    }
                    if (cell.getCellType().equals(BOOLEAN)) {
                        objects[index] = cell.getBooleanCellValue();
                    }
                    if (cell.getCellType().equals(ERROR)) {
                        objects[index] = cell.getErrorCellValue();
                    }
                    index++;
                }
                list.add(objects);
            }
            log.info("导入文件解析成功！");
            return list;
        } catch (Exception e) {
            log.info("导入文件解析失败！错误信息{}", e.getMessage());
        }
        return null;
    }

    /**
     * 将科室字典列表对象转换为导出Excel  表格内容的格式
     *
     * @param zdUnitCodes
     * @return
     */
    private static Map<String, Object> fomartZdUnitCode(List<ZdUnitCode> zdUnitCodes) {
        if (zdUnitCodes == null) {
            return Collections.emptyMap();
        }
        Map<String, Object> data = new HashMap<>();
        data.put(FILE_NAME_KEY, "科室字典.xls");
        List<Map<String, Object>> heads = new ArrayList<>();
        Map<String, Object> map0 = new HashMap<>();
        String[] head0 = {"停用", "科室编码", "科室名称", "分类", "拼音码", "五笔码", "院内码", "门诊开放", "医技上线", "新农合科室编码", "新农合科室名称", "父科室", "收取挂号费", "用药方式执行科室", "门诊挂号就诊", "就诊地点"};
        String[] headNum0 = {"0,0,0,0"};
        map0.put(HEAD_ARR_KEY, head0);
        map0.put(HEAD_NUM_KEY, headNum0);
        heads.add(map0);
        data.put(HEAD_KEY, heads);
        List<String[]> arr = new ArrayList<>();
        zdUnitCodes.forEach(zdUnitCode -> {
            if (zdUnitCode != null) {
                String[] temp = {(zdUnitCode.getDelFlag() == null || YesNoEnum.NO.code.equals(zdUnitCode.getDelFlag())) ? YesNoEnum.NO.name : YesNoEnum.YES.name,
                        zdUnitCode.getCode(),
                        zdUnitCode.getName(),
                        zdUnitCode.getClassValue(),
                        zdUnitCode.getPyCode(),
                        zdUnitCode.getWbCode(),
                        zdUnitCode.getYnCode() == null ? "" : zdUnitCode.getYnCode().toString(),
                        (zdUnitCode.getMzFlag() == null || YesNoEnum.NO.code.equals(zdUnitCode.getMzFlag())) ? YesNoEnum.NO.name : YesNoEnum.YES.name,
                        (zdUnitCode.getYjFlag() == null || YesNoEnum.NO.code.equals(zdUnitCode.getYjFlag())) ? YesNoEnum.NO.name : YesNoEnum.YES.name,
                        zdUnitCode.getXnhDeptCode(),
                        zdUnitCode.getXnhDeptName(),
                        zdUnitCode.getParentName(),
                        (zdUnitCode.getGhChargeFlag() == null || YesNoEnum.NO.code.equals(zdUnitCode.getGhChargeFlag())) ? YesNoEnum.NO.name : YesNoEnum.YES.name,
                        (zdUnitCode.getSupplyFlag() == null || YesNoEnum.NO.code.equals(zdUnitCode.getSupplyFlag())) ? YesNoEnum.NO.name : YesNoEnum.YES.name,
                        (zdUnitCode.getGhjzFlag() == null || YesNoEnum.NO.code.equals(zdUnitCode.getGhjzFlag())) ? YesNoEnum.NO.name : YesNoEnum.YES.name,
                        zdUnitCode.getOfficePos()
                };
                arr.add(temp);
            }
        });
        data.put(DATA_KEY, arr);
        return data;
    }


    /**
     * 将收费清单列表对象转换为导出Excel  表格内容的格式
     *
     * @param chargeFeeVos
     * @return
     */
    private static Map<String, Object> fomartChargeDetail(List<ChargeFeeVo> chargeFeeVos) {
        if (chargeFeeVos == null) {
            return Collections.emptyMap();
        }
        Map<String, Object> data = new HashMap<>();
        data.put(FILE_NAME_KEY, "收费清单.xls");
        List<Map<String, Object>> heads = new ArrayList<>();
        Map<String, Object> map0 = new HashMap<>();
        String[] head0 = {"病人ID", "机制号", "退欠标识", "金额", "发票号", "付款方式", "收费日期"};
        String[] headNum0 = {"0,0,0,0"};
        map0.put(HEAD_ARR_KEY, head0);
        map0.put(HEAD_NUM_KEY, headNum0);
        heads.add(map0);
        data.put(HEAD_KEY, heads);
        List<String[]> arr = new ArrayList<>();
        chargeFeeVos.forEach(chargeFeeVo -> {
            if (chargeFeeVo != null) {
                String[] temp = {chargeFeeVo.getPatientId(),
                        chargeFeeVo.getSerialNo(),
                        chargeFeeVo.getPayMark(),
                        chargeFeeVo.getTotalCharge().setScale(2, BigDecimal.ROUND_HALF_UP).toString(),
                        chargeFeeVo.getReceiptBill(),
                        chargeFeeVo.getChequeType(),
                        DateFormatUtils.format(chargeFeeVo.getChargeDate(), "yyyy-MM-dd HH:mm:ss")
                };
                arr.add(temp);
            }
        });
        data.put(DATA_KEY, arr);
        return data;
    }


    /**
     * 将挂号清单列表对象转换为导出Excel  表格内容的格式
     *
     * @param reqrecVos
     * @return
     */
    private static Map<String, Object> fomartReqrec(List<ReqrecVo> reqrecVos) {
        if (reqrecVos == null) {
            return Collections.emptyMap();
        }
        Map<String, Object> data = new HashMap<>();
        data.put(FILE_NAME_KEY, "挂号清单.xls");
        List<Map<String, Object>> heads = new ArrayList<>();
        Map<String, Object> map0 = new HashMap<>();
        String[] head0 = {"收据号", "机制号", "病人ID", "病人姓名", "科别", "号别", "状态", "金额", "付款方式", "挂号日期"};
        String[] headNum0 = {"0,0,0,0"};
        map0.put(HEAD_ARR_KEY, head0);
        map0.put(HEAD_NUM_KEY, headNum0);
        heads.add(map0);
        data.put(HEAD_KEY, heads);
        List<String[]> arr = new ArrayList<>();
        reqrecVos.forEach(reqrecVo -> {
            if (reqrecVo != null) {
                String[] temp = {reqrecVo.getReceiptBill(),
                        reqrecVo.getSerialNo(),
                        reqrecVo.getPatientId(),
                        reqrecVo.getName(),
                        reqrecVo.getUnitCode(),
                        reqrecVo.getChargeType(),
                        reqrecVo.getCancelMark(),
                        reqrecVo.getChargeFee().setScale(2, BigDecimal.ROUND_HALF_UP).toString(),
                        reqrecVo.getPaymode(),
                        DateFormatUtils.format(reqrecVo.getOpDay(), "yyyy-MM-dd HH:mm:ss")
                };
                arr.add(temp);
            }
        });
        data.put(DATA_KEY, arr);
        return data;
    }


    /**
     * 将门诊收入明细列表对象转换为导出Excel  表格内容的格式
     *
     * @param thmzmxsrs
     * @return
     */
    private static Map<String, Object> fomartThmzmxsr(List<Mzmxsr> thmzmxsrs) {
        if (thmzmxsrs == null) {
            return Collections.emptyMap();
        }
        Map<String, Object> data = new HashMap<>();
        data.put(FILE_NAME_KEY, "门诊明细收入.xls");
        List<Map<String, Object>> heads = new ArrayList<>();
        Map<String, Object> map0 = new HashMap<>();
        String[] head0 = {"姓名", "病人ID","缴费时间", "就诊/申请科室", "就诊/申请医生", "执行科室", "收费项目", "核算码", "父类码", "数量", "单价", "金额"};
        String[] headNum0 = {"0,0,0,0"};
        map0.put(HEAD_ARR_KEY, head0);
        map0.put(HEAD_NUM_KEY, headNum0);
        heads.add(map0);
        data.put(HEAD_KEY, heads);
        List<String[]> arr = new ArrayList<>();
        thmzmxsrs.forEach(thmzmxsr -> {
            if (thmzmxsr != null) {
                Double quty = thmzmxsr.getQuty();
                BigDecimal price = thmzmxsr.getPrice();
                BigDecimal je = thmzmxsr.getJe();
                Date chargeDate= thmzmxsr.getChargeDate();
                String[] temp = {thmzmxsr.getXm(),
                        thmzmxsr.getPatientId(),
                        DateFormatUtils.format(chargeDate, "yyyy-MM-dd HH:mm:ss"),
                        thmzmxsr.getJzSqDept(),
                        thmzmxsr.getJzSqDoctor(),
                        thmzmxsr.getExecDept(),
                        thmzmxsr.getXmm(),
                        thmzmxsr.getHsm(),
                        thmzmxsr.getParentCode(),
                        quty == null ? "0" : quty.toString(),
                        price == null ? "0.00" : price.toString(),
                        je == null ? "0.00" : je.toString()
                };
                arr.add(temp);
            }
        });
        data.put(DATA_KEY, arr);
        return data;
    }


    /**
     * 将门诊挂号列表对象转换为导出Excel  表格内容的格式
     *
     * @param mzyReqrecList
     * @return
     */
    private static Map<String, Object> fomartReqrecList(List<MzyReqrecVo> mzyReqrecList) {
        if (mzyReqrecList == null) {
            return Collections.emptyMap();
        }
        Map<String, Object> data = new HashMap<>();
        data.put(FILE_NAME_KEY, "门诊挂号统计.xls");
        List<Map<String, Object>> heads = new ArrayList<>();
        Map<String, Object> map0 = new HashMap<>();
        String[] head0 = {"病人姓名", "诊疗卡号" ,"病人ID", "挂号科室", "挂号医生", "挂号时间", "挂号费", "诊查费", "其他收费","就诊状态"};
        String[] headNum0 = {"0,0,0,0"};
        map0.put(HEAD_ARR_KEY, head0);
        map0.put(HEAD_NUM_KEY, headNum0);
        heads.add(map0);
        data.put(HEAD_KEY, heads);
        List<String[]> arr = new ArrayList<>();
        mzyReqrecList.forEach(mzyReqrecVo -> {
            if (mzyReqrecVo != null) {
                MzyReqrec mzyReqrec=mzyReqrecVo.getMzyReqrec();
                String status = "挂号";
                if(mzyReqrec.getCancelMark()==0){
                    if(mzyReqrec.getVisitedMark()==1){
                        status = "已诊";
                    }
                }else if (mzyReqrec.getCancelMark() == 1) {
                    status = "退号";
                }
                String[] temp = {mzyReqrec.getName(),
                        mzyReqrecVo.getMzPatientMi().getIcCardNo(),
                        mzyReqrec.getPatientId(),
                                mzyReqrec.getUnitCode(),
                                mzyReqrec.getDoctorCode(),
                                DateFormatUtils.format(mzyReqrec.getRequestDay(), "yyyy-MM-dd HH:mm:ss"),
                                mzyReqrec.getReqFee()==null?"0":mzyReqrec.getReqFee().toString(),
                                mzyReqrec.getClinicFee()==null?"0":mzyReqrec.getClinicFee().toString(),
                                mzyReqrec.getOthFee()==null?"0":mzyReqrec.getOthFee().toString(),status
                };
                arr.add(temp);
            }
        });
        data.put(DATA_KEY, arr);
        return data;
    }

}