package thyyxxk.webserver.service.inpatient.casefrontsheet;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import thyyxxk.webserver.config.exception.BizException;
import thyyxxk.webserver.constants.frntsheet.DismissWay;
import thyyxxk.webserver.constants.frntsheet.Hbsag;
import thyyxxk.webserver.constants.frntsheet.Provinces;
import thyyxxk.webserver.dao.his.inpatient.casefrontsheet.FrontSheetExportDao;
import thyyxxk.webserver.entity.casefrontsheet.CaseFrontsheetDisdiag;
import thyyxxk.webserver.entity.casefrontsheet.CaseFrontsheetSurgery;
import thyyxxk.webserver.entity.casefrontsheet.request.ExportDclRequest;
import thyyxxk.webserver.entity.casefrontsheet.request.ExportHistorySheets;
import thyyxxk.webserver.entity.casefrontsheet.response.ExportDclResponse;
import thyyxxk.webserver.entity.casefrontsheet.response.HistorySheet;
import thyyxxk.webserver.entity.casefrontsheet.response.SheetForHqms;
import thyyxxk.webserver.entity.dictionary.CodeName;
import thyyxxk.webserver.entity.login.UserInfo;
import thyyxxk.webserver.service.hutoolcache.*;
import thyyxxk.webserver.utils.*;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Service
public class CaseFrontSheetExportService {
    private final FrontSheetExportDao dao;
    private final UserCache userCache;
    private final DeptCache deptCache;
    private final NationCache nationCache;
    private final CountryCache countryCache;
    private final OccupationCache occupationCache;

    @Autowired
    public CaseFrontSheetExportService(FrontSheetExportDao dao, UserCache userCache, DeptCache deptCache, NationCache nationCache, CountryCache countryCache, OccupationCache occupationCache) {
        this.dao = dao;
        this.userCache = userCache;
        this.deptCache = deptCache;
        this.nationCache = nationCache;
        this.countryCache = countryCache;
        this.occupationCache = occupationCache;
    }

    public List<SheetForHqms> fetchSheets(String month, boolean isHqms) {
        String begin = month + "-01 00:00:00.000";
        String end = DateUtil.getMonthEndtime(month);
        List<SheetForHqms> list =  isHqms ? dao.fetchSheets2(begin, end) : dao.fetchSheets(begin, end);
        for (SheetForHqms sheet : list) {
            if (Objects.equals(sheet.getZyAdmissWay(), "4")) {
                sheet.setZyAdmissWay("2");
            }
            sheet.setSurgicalFee(DecimalUtil.add(sheet.getAnesthetizeFee(), sheet.getSurgeryFee()));
            sheet.setSurgeryList(selectSurgeries(sheet.getBah(), sheet.getAdmissTimes(), isHqms));
            sheet.setDisdiagList(selectDiags(sheet.getBah(), sheet.getAdmissTimes()));
            sheet.setZyDismissWay(DismissWay.getWjwCodeByHisCode(sheet.getZyDismissWay()));
            sheet.setHbsAg(Hbsag.getWjwCodeByHisCode(sheet.getHbsAg()));
            sheet.setPayMethod(filterPayMethod(sheet.getPayMethod(), sheet.getSocialNo()));
            sheet.setRh(filterRh(sheet.getRh()));

            String orintv = sheet.getNativePlace();
            if (StringUtil.notBlank(orintv) && orintv.length() > 1) {
                String ntvplc = sheet.getNativePlace().substring(0, 2);
                sheet.setNativePlace(Provinces.getWjwCodeByHisCode(ntvplc));
            }

            sheet.setCountry(countryCache.getCountryName(sheet.getCountry()));
            sheet.setAdmissDeptCode(deptCache.get(sheet.getAdmissDeptCode()).getWjwCode());
            sheet.setZkWardCode(deptCache.get(sheet.getZkWardCode()).getWjwCode());
            sheet.setDismissDeptCode(deptCache.get(sheet.getDismissDeptCode()).getWjwCode());
            sheet.setNation(nationCache.get(sheet.getNation()).getWjwCode());
        }
        list.removeIf(item -> item.getPathologicDiagStr().contains(",") || item.getDisdiagList().isEmpty());
        return list;
    }

    private List<CaseFrontsheetDisdiag> selectDiags(String bah, int times) {
        List<CaseFrontsheetDisdiag> diags = dao.fetchDiags(bah, times);
        diags.removeIf(item -> item.getName().contains(","));
        return diags;
    }

    private List<CaseFrontsheetSurgery> selectSurgeries(String bah, int times, boolean isHqms) {
        List<CaseFrontsheetSurgery> surgeries = dao.fetchSurgeries(bah, times);
        surgeries.removeIf(item -> StringUtil.isBlank(item.getName()) || item.getName().contains(","));
        for (CaseFrontsheetSurgery s : surgeries) {
            s.setName(s.getName().replaceAll(",", "，"));
            int cut = 0;
            if (StringUtil.notBlank(s.getCut())) {
                cut = Integer.parseInt(s.getCut());
            }
            int heal = 0;
            if (StringUtil.notBlank(s.getHeal())) {
                heal = Integer.parseInt(s.getHeal());
            }
            if (cut == 0 || heal == 0) {
                s.setWjwCutHeal(0);
            } else {
                int wjwCutHeal = (cut - 1) * cut + heal + negationCalculatingResidue(cut);
                s.setWjwCutHeal(wjwCutHeal);
            }
            if (isHqms) {
                StringUtil.nullIf(s.getLevel(), "-");
                StringUtil.nullIf(s.getAssistantOne(), "-");
                StringUtil.nullIf(s.getAssistantOneName(), "-");
                StringUtil.nullIf(s.getAssistantTwo(), "-");
                StringUtil.nullIf(s.getAssistantTwoName(), "-");
                StringUtil.nullIf(s.getAnaesthesia(), "-");
                StringUtil.nullIf(s.getAnaesthesiaor(), "-");
                StringUtil.nullIf(s.getAnaesthesiaorName(), "-");
            }
        }
        return surgeries;
    }

    private String filterPayMethod(String method, String idNumber) {
        if (StringUtil.isBlank(method)) {
            return "9";
        }
        int tempVal = Integer.parseInt(method);
        if (tempVal > 3) {
            return method;
        }
        if (idNumber.startsWith("4301")) {
            return method + ".1";
        }
        return method + ".2";
    }

    private String filterRh(String rh) {
        if (StringUtil.isBlank(rh) || rh.equals("0")) {
            return "4";
        }
        return rh;
    }

    private int negationCalculatingResidue(int source) {
        return source % 2 == 0 ? 1 : 0;
    }

    public List<ExportDclResponse> getExportableDclData(ExportDclRequest request) {
        switch (request.getType()) {
            case "DUPLICATE":
                return dao.getDuplicateSheets(request.getBegin(), request.getEnd());
            case "CLOSEDOWN":
                return dao.getCloseDownSheets(request.getBegin(), request.getEnd());
            case "LENDOUT":
                return dao.getLendOutSheets(request.getBegin(), request.getEnd());
            default:
                return new ArrayList<>();
        }
    }

    public void getHistorySheets(ExportHistorySheets request, HttpServletResponse response) {
        UserInfo userInfo = userCache.getUserInfoByToken();
        String statement = "";
        StringBuilder builder = new StringBuilder();
        if (!userInfo.getRoles().contains(1) && !userInfo.getRoles().contains(70)) {
            builder.append(",'").append(userInfo.getDeptCode()).append("'");
            for (String item : userInfo.getPartTimeDept()) {
                builder.append(",'").append(item).append("'");
            }
            statement = "and a.dismiss_dept_code in (" + builder.substring(1) + ")";
        }
        JSONArray array = new JSONArray();
        AtomicInteger maxDiagSize = new AtomicInteger(1);
        AtomicInteger maxSurgerySize = new AtomicInteger(1);
        dao.selectHistorySheet2(request.getStart(), request.getEnd(), statement, result -> {
            HistorySheet sheet = result.getResultObject();
            sheet.setSex(FilterUtil.translateGender(sheet.getSex()));
            sheet.setZyAdmissWay(FilterUtil.translateAdmissWay(sheet.getZyAdmissWay()));
            sheet.setQualityControlLevel(FilterUtil.translateQualityLevel(sheet.getQualityControlLevel()));
            sheet.setZyDismissWay(FilterUtil.translateDismissWay(sheet.getZyDismissWay()));
            sheet.setMonopathyManagement(FilterUtil.translateYesOrNo(sheet.getMonopathyManagement()));
            sheet.setUseAntibiotic(FilterUtil.translateYesOrNo(sheet.getUseAntibiotic()));
            sheet.setBacilliculture(FilterUtil.translateYesOrNo(sheet.getBacilliculture()));
            sheet.setClinicalPathwayManagement(FilterUtil.translateClnclPthwyMngmnt(sheet.getClinicalPathwayManagement()));
            sheet.setDrgsManagement(FilterUtil.translateDrgsManagement(sheet.getDrgsManagement()));
            sheet.setStatutoryEpidemic(FilterUtil.translateStatutoryEpidemic(sheet.getStatutoryEpidemic()));
            sheet.setPayMethod(FilterUtil.translatePayMethod(sheet.getPayMethod()));
            sheet.setCountry(countryCache.getCountryName(sheet.getCountry()));
            sheet.setNation(nationCache.get(sheet.getNation()).getName());
            sheet.setOccupation(occupationCache.getOccupationName(sheet.getOccupation()));
            sheet.setMarriage(FilterUtil.translateMarriage(sheet.getMarriage()));
            sheet.setContactRelation(FilterUtil.translateRelation(sheet.getContactRelation()));
            sheet.setHasSurgery(FilterUtil.translateHasSurgery(sheet.getHasSurgery()));
            sheet.setAllergy(FilterUtil.translateHaveOrNot(sheet.getAllergy()));
            sheet.setAutopsy(FilterUtil.translateYesOrNo(sheet.getAutopsy()));
            sheet.setHbsAg(FilterUtil.translateHbsAg(sheet.getHbsAg()));
            sheet.setHcvAb(FilterUtil.translateHbsAg(sheet.getHcvAb()));
            sheet.setHivAb(FilterUtil.translateHbsAg(sheet.getHivAb()));
            sheet.setTpAb(FilterUtil.translateHbsAg(sheet.getTpAb()));
            sheet.setRh(FilterUtil.translateHbsAg(sheet.getRh()));
            sheet.setBloodType(FilterUtil.translateBloodType(sheet.getBloodType()));
            sheet.setAdmissAgainInOneMonth(FilterUtil.translateHaveOrNot(sheet.getAdmissAgainInOneMonth()));
            sheet.setDiagConform1(FilterUtil.translateDiagConform(sheet.getDiagConform1()));
            sheet.setDiagConform2(FilterUtil.translateDiagConform(sheet.getDiagConform2()));
            sheet.setDiagConform3(FilterUtil.translateDiagConform(sheet.getDiagConform3()));
            sheet.setDiagConform4(FilterUtil.translateDiagConform(sheet.getDiagConform4()));
            sheet.setDiagConform5(FilterUtil.translateDiagConform(sheet.getDiagConform5()));
            sheet.setCaseClassification(FilterUtil.translateCaseClass(sheet.getCaseClassification()));
            sheet.setHasIcu(FilterUtil.translateHaveOrNot(sheet.getHasIcu()));
            String[] diagCodeArr = sheet.getDisdiagCodeStr().split("\\^");
            String[] diagNameArr = sheet.getDisdiagNameStr().split("\\^");
            String[] surgeryCodeArr = sheet.getSurgeryCodeStr().split("\\^");
            String[] surgeryNameArr = sheet.getSurgeryNameStr().split("\\^");
            String[] surgeryLevelArr = sheet.getSurgeryLevelStr().split("\\^");
            sheet.setDisdiag0(makeExportFormat(diagCodeArr[0], diagNameArr[0]));

            sheet.setSurgery0(makeExportFormat(surgeryCodeArr[0], surgeryNameArr[0], surgeryLevelArr[0]));
            String jstring = JSONObject.toJSONString(sheet, SerializerFeature.WriteMapNullValue);
            JSONObject obj = JSONObject.parseObject(jstring);
            if (request.needAllDiagnoses() && diagCodeArr.length > 1 && diagNameArr.length > 1) {
                for (int i = 1; i < diagCodeArr.length; i++) {
                    obj.put("disdiag" + i, makeExportFormat(diagCodeArr[i], diagNameArr[i]));
                }
                maxDiagSize.set(Math.max(maxDiagSize.get(), diagCodeArr.length));
            }
            if (request.needAllSurgeries() && surgeryCodeArr.length > 1 && surgeryNameArr.length > 1) {
                for (int i = 1; i < surgeryCodeArr.length; i++) {
                    obj.put("surgery" + i, makeExportFormat(surgeryCodeArr[i], surgeryNameArr[i], surgeryLevelArr[i]));
                }
                maxSurgerySize.set(Math.max(maxSurgerySize.get(), surgeryCodeArr.length));
            }
            array.add(obj);
        });
        if (array.isEmpty()) {
            throw new BizException("没有可以导出的数据。");
        }
        JSONObject first = array.getJSONObject(0);
        for (int i = 0; i < 27; i++) {
            first.putIfAbsent("disdiag" + i, "");
            first.putIfAbsent("surgery" + i, "");
        }

        ToolExcel excel = new ToolExcel();
        for (CodeName field : request.getField()) {
            excel.addTitle(field.getCode(), field.getName());
        }

        excel.addTitle("disdiag0", "主要诊断", 30);
        for (int i = 1; i < maxDiagSize.get(); i++) {
            excel.addTitle("disdiag" + i, "其他诊断" + i, 30);
        }

        excel.addTitle("surgery0", "主要手术", 30);
        for (int i = 1; i < maxSurgerySize.get(); i++) {
            excel.addTitle("surgery" + i, "其他手术" + i, 30);
        }
        excel.exportExcel(array, response);
    }

    private String makeExportFormat(String code, String name, String surgeryLevel) {
        if (StringUtil.isBlank(code)) {
            return null;
        }
        String result = "[" + code + "] " + name;
        if (null == surgeryLevel) {
            return result;
        }
        if (surgeryLevel.equals("none")) {
            surgeryLevel = "未知级别";
        } else {
            surgeryLevel += "级手术";
        }
        result = result + "（" + surgeryLevel + "）";
        return result;
    }

    private String makeExportFormat(String code, String name) {
        return makeExportFormat(code, name, null);
    }
}
