package thyyxxk.webserver.service.inpatient.casefrontsheet;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.constants.frntsheet.DismissWay;
import thyyxxk.webserver.dao.his.inpatient.casefrontsheet.SheetSearchDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.casefrontsheet.response.StatisticsBySeason;
import thyyxxk.webserver.entity.dictionary.CodeName;
import thyyxxk.webserver.entity.dictionary.SearchDataParam;
import thyyxxk.webserver.service.inpatient.DictionaryService;
import thyyxxk.webserver.utils.ExcelUtil;
import thyyxxk.webserver.utils.ResultVoUtil;
import thyyxxk.webserver.utils.StringUtil;

import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * @author dj
 */
@Slf4j
@Service
public class CaseFrontSheetSearchService {
    private final SheetSearchDao dao;
    private final DictionaryService service;
    private Map<String, CodeName> diagMap;

    @Autowired
    public CaseFrontSheetSearchService(SheetSearchDao dao, DictionaryService service) {
        this.dao = dao;
        this.service = service;
    }

    public ResultVo<List<CodeName>> sheetSearch(SearchDataParam param) {
        final String content = '%' + param.getContent().toUpperCase() + '%';
        switch (param.getTarget()) {
            case "surgery":
                return ResultVoUtil.success(searchSurgery(param.getMethod(), content, param.getPage() - 1));
            case "pathologicDiag":
                return ResultVoUtil.success(searchPathologicDiag(param.getMethod(), content, param.getPage() - 1));
            case "place":
                return ResultVoUtil.success(searchBirthPlace(param.getMethod(), content, param.getPage() - 1));
            case "normalDiag":
                return ResultVoUtil.success(searchNormalDiag(param.getMethod(), content, param.getPage() - 1));
            case "clinicdiag":
                return ResultVoUtil.success(searchClinicDiag(param.getMethod(), content, param.getPage() - 1));
            case "hurtReason":
                return ResultVoUtil.success(searchHurtReason(param.getMethod(), content, param.getPage() - 1));
            case "employee":
                return ResultVoUtil.success(searchEmployee(param.getMethod(), content, param.getPage() - 1));
            case "diag":
                return service.searchYbDiag(param);
            default:
                return ResultVoUtil.success(new ArrayList<>());
        }
    }

    private List<CodeName> searchSurgery(String method, String content, int page) {
        if (method.equals("alpha")) {
            method = "py_code";
        } else if (method.equals("code")) {
            method = "code";
        } else {
            method = "name";
        }
        return dao.searchSurgery(method, content, page);
    }

    private List<CodeName> searchNormalDiag(String method, String content, int page) {
        if (method.equals("alpha")) {
            method = "py_code";
        }
        return dao.searchNormalDiag(method, content, page);
    }

    private List<CodeName> searchClinicDiag(String method, String content, int page) {
        if (method.equals("alpha")) {
            method = "yb_py_code";
        } else if (method.equals("code")) {
            method = "yb_code";
        } else {
            method = "yb_name";
        }
        return dao.searchClinicDiag(method, content, page);
    }

    private List<CodeName> searchPathologicDiag(String method, String content, int page) {
        if (method.equals("alpha")) {
            method = "py_code";
        } else if (method.equals("code")) {
            method = "code";
        } else {
            method = "name";
        }
        return dao.searchPathologicDiag(method, content, page);
    }

    private List<CodeName> searchBirthPlace(String method, String content, int page) {
        if (method.equals("alpha")) {
            method = "py_code";
        }
        return dao.searchBirthPlace(method, content, page);
    }

    private List<CodeName> searchHurtReason(String method, String content, int page) {
        if (method.equals("alpha")) {
            method = "py_code";
        }
        return dao.searchHurtReason(method, content, page);
    }

    private List<CodeName> searchEmployee(String method, String content, int page) {
        if (method.equals("alpha")) {
            method = "py_code";
        }
        return dao.searchEmployee(method, content, page);
    }

    public ResultVo<List<CodeName>> getSsfzSurgeriesByIcd(String bah, int times, String icd) {
        String mainMedinsDiag = dao.selectMainMedinsDiag(bah, times);
        if (StringUtil.isBlank(mainMedinsDiag)) {
            mainMedinsDiag = dao.selectMedinsDiagReflect(icd);
        }
        String diseCode = StringUtil.isBlank(mainMedinsDiag) ? icd : mainMedinsDiag;
        String disefamilyCode = dao.selectDisefamilyCode(diseCode);
        if (StringUtil.isBlank(disefamilyCode)) {
            return ResultVoUtil.fail(ExceptionEnum.SLIGHTLY_ERROR);
        }
        List<CodeName> result = dao.selectOperationDisefamilies(disefamilyCode);
        if (null == result || result.isEmpty()) {
            return ResultVoUtil.fail(ExceptionEnum.SLIGHTLY_ERROR);
        }
        return ResultVoUtil.success(result);
    }

    /**
     * 1.	报送范围为出院日期在2019年1月1日—2021年12月31日，包括城镇职工、城乡居民基本医疗保险病人的住院数据（排除全自费、异地就医、工伤、生育保险类住院数据）；
     * 2.	NO41表以CSV文件格式提取，并按季度上传数据。单个上传文件上限为5万条病例数，如果数据量过大，也可按月度上传数据。（文件命名格式：“医疗机构名称_201901.csv”）；
     * 3.	报送规范以《长株潭数据报送标准-附件1、2》为准，相关编码要按照贯标后报送，疾病编码、手术编码要按照医保编码2.0目录报送，AKC190、AKB020作为唯一联合主键。
     * */
    public void fetchStatisticsBySeason(HttpServletResponse response, String season) {
        if (null == diagMap) {
            diagMap = new HashMap<>();
        }
        String[] range = getRangeBySeason(season);
        List<StatisticsBySeason> list = dao.selectStatisticsBySeason(range[0], range[1]);
        list.removeIf(itm -> StringUtil.isBlank(itm.getDisdiagCode()));
        int column = 0;
        String[][] content = new String[list.size()][17];
        String[] title = {"住院号", "机构编码", "机构名称", "住院次数", "病案号", "姓名", "性别", "出生日期", "年龄", "国籍",
                "身份证号", "职业", "婚姻", "入院日期", "出院日期", "住院天数", "诊断名称", "诊断编码", "离院方式", "住院费用"};
        for (StatisticsBySeason item : list) {
            item.setDismissWay(DismissWay.getWjwCodeByHisCode(item.getDismissWay()));
            if (dao.medinsDiagExist(item.getDisdiagCode()) == 0) {
                CodeName mapRes = diagMap.get(item.getDisdiagCode());
                if (null != mapRes) {
                    item.setDisdiagCode(mapRes.getCode());
                    item.setDisdiagName(mapRes.getName());
                } else {
                    String tmpcode = item.getDisdiagCode().split("\\.")[0];
                    List<CodeName> medinsdiags = dao.selectMedinsDiags(tmpcode);
                    if (null != medinsdiags && !medinsdiags.isEmpty()) {
                        CodeName target = null;
                        double simVal = 0;
                        for (CodeName diag : medinsdiags) {
                            double dsm = StringUtil.getSimilarDegree(item.getDisdiagName(), diag.getName());
                            log.info("解析：HIS诊断：【{}，{}】, 医保诊断：【{}，{}】, 相似度：【{}】",
                                    item.getDisdiagCode(), item.getDisdiagName(), diag.getCode(), diag.getName(), dsm);
                            if (dsm > simVal) {
                                simVal = dsm;
                                target = diag;
                            }
                            if (dsm > .95) {
                                break;
                            }
                        }
                        if (simVal >= .3) {
                            log.info("使用医保2.0诊断【{}，{}】，与原诊断【{}，{}】相似度为【{}】",
                                    target.getCode(), target.getName(), item.getDisdiagCode(), item.getDisdiagName(), simVal);
                            diagMap.put(item.getDisdiagCode(), target);
                            item.setDisdiagCode(target.getCode());
                            item.setDisdiagName(target.getName());
                        } else {
                            log.info("没有符合相似度条件的诊断，维持原样。");
                        }
                    }
                }
            }
            content[column] = new String[title.length];
            content[column][0] = item.getPatNo();
            content[column][1] = item.getHospId();
            content[column][2] = item.getHospName();
            content[column][3] = item.getTimes();
            content[column][4] = item.getBah();
            content[column][5] = item.getName();
            content[column][6] = item.getGender();
            content[column][7] = item.getBirthdate();
            content[column][8] = item.getAge();
            content[column][9] = item.getCountry();
            content[column][10] = item.getSocialNo();
            content[column][11] = item.getOccupation();
            content[column][12] = item.getMarriage();
            content[column][13] = item.getAdmissDate();
            content[column][14] = item.getDisDate();
            content[column][15] = item.getInHospDays();
            content[column][16] = item.getDisdiagName();
            content[column][17] = item.getDisdiagCode();
            content[column][18] = item.getDismissWay();
            content[column][19] = item.getTotalCharge();
            column ++;
        }

//        Queue<String> queue = SiUtil.readTxtFile("D:\\disdiagwrong.txt");
//        if (null == queue) {
//            log.info("读取文本为空！");
//            return;
//        }
//        log.info("读取文本共 {} 行", queue.size());
//        String[][] content = new String[queue.size()][];
//        int count = 0;
//        String[] title = {"patNo", "times", "name", "disdate", "diag" };
//        int column = 0;
//        Map<String, String> resolvedMap = new HashMap<>();
//        while (!queue.isEmpty()) {
//            String info = queue.poll();
//            String[] ifs = info.split("\t");
//            PureCodeName hisDiag = dao.selectMainDisDiag(ifs[1], ifs[2]);
//            if (null != hisDiag && StringUtil.notBlank(hisDiag.getCode()) && StringUtil.notBlank(hisDiag.getName())) {
//                String resolvedDiag = resolvedMap.get(hisDiag.getCode());
//                if (StringUtil.notBlank(resolvedDiag)) {
//                    content[column] = new String[title.length];
//                    content[column][0] = ifs[1];
//                    content[column][1] = ifs[2];
//                    content[column][2] = ifs[3];
//                    content[column][3] = ifs[4];
//                    content[column][4] = ifs[5];
//                    column += 1;
//                    count += 1;
//                    continue;
//                }
//                List<PureCodeName> medinsDiags = dao.selectMedinsDiags(hisDiag.getCode().substring(0,3));
//                if (null != medinsDiags && !medinsDiags.isEmpty()) {
//                    double simVal = 0;
//                    PureCodeName target = hisDiag;
//                    for (PureCodeName diag : medinsDiags) {
//                        double dsm = StringUtil.getSimilarDegree(hisDiag.getName(), diag.getName());
//                        log.info("解析：HIS诊断：【{}，{}】, 医保诊断：【{}，{}】, 相似度：【{}】",
//                                hisDiag.getCode(), hisDiag.getName(), diag.getCode(), diag.getName(), dsm);
//                        if (dsm > simVal) {
//                            simVal = dsm;
//                            target = diag;
//                        }
//                    }
//                    count += 1;
//                    ifs[5] = target.getCode();
//                    resolvedMap.put(hisDiag.getCode(), target.getCode());
//                    log.info("【{}, {}】使用医保2.0诊断【{}，{}】，与原诊断【{}，{}】相似度为【{}】",
//                            ifs[1], ifs[2], target.getCode(), target.getName(), hisDiag.getCode(), hisDiag.getName(), simVal);
//                }
//
//            }
//            content[column] = new String[title.length];
//            content[column][0] = ifs[1];
//            content[column][1] = ifs[2];
//            content[column][2] = ifs[3];
//            content[column][3] = ifs[4];
//            content[column][4] = ifs[5];
//            column ++;
//        }
//        log.info("共有 {} 条数据，已处理 {} 条", content.length, count);
        ExcelUtil.exportExcel(response, title, content);
    }

    private String[] getRangeBySeason(String season) {
        String begntime;
        String endtime;
        switch (season) {
            case "2019S1":
                begntime = "2019-01-01 00:00:00.000";
                endtime = "2019-03-31 23:59:59.000";
                break;
            case "2019S2":
                begntime = "2019-04-01 00:00:00.000";
                endtime = "2019-06-30 23:59:59.000";
                break;
            case "2019S3":
                begntime = "2019-07-01 00:00:00.000";
                endtime = "2019-09-30 23:59:59.000";
                break;
            case "2019S4":
                begntime = "2019-10-01 00:00:00.000";
                endtime = "2019-12-31 23:59:59.000";
                break;
            case "2020S1":
                begntime = "2020-01-01 00:00:00.000";
                endtime = "2020-03-31 23:59:59.000";
                break;
            case "2020S2":
                begntime = "2020-04-01 00:00:00.000";
                endtime = "2020-06-30 23:59:59.000";
                break;
            case "2020S3":
                begntime = "2020-07-01 00:00:00.000";
                endtime = "2020-09-30 23:59:59.000";
                break;
            case "2020S4":
                begntime = "2020-10-01 00:00:00.000";
                endtime = "2020-12-31 23:59:59.000";
                break;
            case "2021S1":
                begntime = "2021-01-01 00:00:00.000";
                endtime = "2021-03-31 23:59:59.000";
                break;
            case "2021S2":
                begntime = "2021-04-01 00:00:00.000";
                endtime = "2021-06-30 23:59:59.000";
                break;
            case "2021S3":
                begntime = "2021-07-01 00:00:00.000";
                endtime = "2021-09-30 23:59:59.000";
                break;
            case "2021S4":
            default:
                begntime = "2021-10-01 00:00:00.000";
                endtime = "2021-12-31 23:59:59.000";
                break;
        }
        return new String[]{begntime, endtime};
    }
}
