package thyyxxk.webserver.service.medicalinsurance;

import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.constants.Message;
import thyyxxk.webserver.constants.sidicts.Insutype;
import thyyxxk.webserver.constants.sidicts.MedType;
import thyyxxk.webserver.dao.his.medicalinsurance.SiSettleApplyDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.medicalinsurance.inpatient.settleapply.request.SettledApplyInquiry;
import thyyxxk.webserver.entity.medicalinsurance.inpatient.settleapply.response.SiSettleApply;
import thyyxxk.webserver.entity.inpatient.dismiss.ZyDisYbDiag;
import thyyxxk.webserver.entity.inpatient.dismiss.ZyDisYbSrgry;
import thyyxxk.webserver.entity.inpatient.patient.Patient;
import thyyxxk.webserver.entity.inpatient.patient.ZyInYbDiag;
import thyyxxk.webserver.service.hutoolcache.RegionCache;
import thyyxxk.webserver.service.hutoolcache.UserCache;
import thyyxxk.webserver.http.websocket.SocketV2;
import thyyxxk.webserver.http.websocket.dto.WebSocketByListUserCode;
import thyyxxk.webserver.service.inpatient.casefrontsheet.CaseFrontSheetMainService;
import thyyxxk.webserver.service.inpatient.PatientService;
import thyyxxk.webserver.utils.*;

import java.time.LocalTime;
import java.util.*;


/**
 * @author dj
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SiSettleApplyService {
    private final SiSettleApplyDao dao;
    private final PatientService ptntSrvc;
    private final CaseFrontSheetMainService csfrntSrvc;
    private static final Integer APPROVED = 1;
    private static final Integer REAL_SETTLE = 1;
    private static final Integer MIDDLE_SETTLE = 2;
    private final SocketV2 intergrationPlatformSocket;
    private final RegionCache regionCache;
    private final UserCache userCache;

    public ResultVo<SiSettleApply> selectSettleApply(Patient p) {
        int type = p.getMidSetl() ? MIDDLE_SETTLE : REAL_SETTLE;
        if (type == MIDDLE_SETTLE) {
            int totalCost = dao.selectTotalCharge(p.getPatNo(), p.getAdmissTimes(), p.getLedgerSn());
            if (totalCost <= 0) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "患者总费用为0，不能进行中间断账。");
            }
        }
        String mdtrtId = dao.selectMdtrtId(p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn());
        if (StringUtil.isBlank(mdtrtId) || p.getInpatientNo().startsWith("JT")) {
            SiSettleApply apply = new SiSettleApply();
            apply.setStatus(APPROVED);
            return ResultVoUtil.success(apply);
        }
        Date disdate = null;
        if (type == REAL_SETTLE) {
            List<Date> tempList = dao.selectActOrderDisDate2("yz_act_order", p.getInpatientNo(), p.getAdmissTimes());
            if (tempList.isEmpty()) {
                tempList = dao.selectActOrderDisDate2("yz_inact_order", p.getInpatientNo(), p.getAdmissTimes());
            }
            if (tempList.isEmpty()) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "患者没有出院医嘱，无法申请出院结算！");
            }
            if (tempList.size() > 1) {
                return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "患者有多条出院医嘱，请检查。");
            }
            disdate = tempList.get(0);
        }
        SiSettleApply apply = dao.selectSettleApply(p.getInpatientNo(), p.getAdmissTimes(), p.getLedgerSn(), type);
        if (null == apply) {
            apply = new SiSettleApply();
            apply.setSortNo(0);
            if (type == REAL_SETTLE) {
                apply.setSettleDatetime(disdate);
            }
        }
        return ResultVoUtil.success(apply);
    }

    public ResultVo<String> submitSettleApply(SiSettleApply apply) {
        if (StringUtil.isBlank(apply.getInputComment())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "申请理由不能为空！");
        }
        apply.setStatus(0);
        apply.setSortNo(apply.getSortNo() + 1);
        apply.setInputStaff(TokenUtil.getInstance().getTokenUserId());

        if (!isWorkingHours()) {
            apply.setHandleComment("非工作时间自动审核。");
            apply.setHandleStaff("99995");
            apply.setHandleStaffName("泰和住院系统");
            apply.setHandleDatetime(new Date());
            apply.setStatus(APPROVED);
            dao.insertSettleApply(apply);
            String msg = "自动审核已通过。";
            return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_ALERT, msg, msg);
        }

        dao.insertSettleApply(apply);
        Set<String> codes = dao.selectUserCodeByGroupId("3020100");

        JSONObject messageBody = new JSONObject();
        messageBody.put("title", "提示");
        messageBody.put("message", "【住院号：" + apply.getPatNo() + "】有新的出院申请。");

        String messageWrapper = SocketMsg.socketVo(Message.SYSTEM_NOTIFICATION, messageBody);

        intergrationPlatformSocket.sendUserCodeListMessage(
                WebSocketByListUserCode.create(codes, messageWrapper)
        );

        return ResultVoUtil.success("提交成功。");
    }

    private boolean isWorkingHours() {
        LocalTime currentTime = LocalTime.now();
        LocalTime amStart = LocalTime.of(8, 0);
        LocalTime amEnd = LocalTime.of(12, 0);
        LocalTime pmStart = LocalTime.of(14, 0);
        LocalTime pmEnd = LocalTime.of(17, 30);
        return (currentTime.isAfter(amStart) && currentTime.isBefore(amEnd)) ||
               (currentTime.isAfter(pmStart) && currentTime.isBefore(pmEnd));
    }

    public ResultVo<List<SiSettleApply>> selectUnhandledApplies() {
        List<SiSettleApply> list = dao.selectUnhandledApplies();
        return ResultVoUtil.success(list);
    }

    public ResultVo<Map<String, Object>> selectPatientInfo(SiSettleApply param) {
        ResultVo<Patient> ptntRsvo = param.getInOutFlag() == 1 ?
                ptntSrvc.getPatientInfo(param.getPatNo()) : ptntSrvc.getDisPatient(param.getPatNo(), param.getTimes());
        if (!Objects.equals(ptntRsvo.getCode(), ExceptionEnum.SUCCESS.getCode())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, ptntRsvo.getMessage());
        }
        Patient patient = ptntRsvo.getData();
        SiSettleApply apply = dao.selectCurrentApply(param);
        apply.setGender(param.getGender());
        apply.setName(param.getName());
        apply.setWardName(param.getWardName());
        apply.setMedTypeName(MedType.getName(apply.getMedType()));
        apply.setInsutypeName(Insutype.getName(apply.getInsutype()));
        apply.setInputName(userCache.getEmployeeName(apply.getInputStaff()));
        apply.setInsuplcAdmdvsName(regionCache.get(apply.getInsuplcAdmdvs()));
        if (StringUtil.notBlank(apply.getHandleStaff())) {
            apply.setHandleStaffName(userCache.getEmployeeName(apply.getHandleStaff()));
        }
        List<ZyInYbDiag> inYbDiags = ptntSrvc.getZyInYbDiags(apply.getPatNo(), apply.getTimes()).getData();
        List<ZyDisYbDiag> disYbDiags = ptntSrvc.getZyDisYbDiags(apply.getPatNo(), apply.getTimes()).getData();
        List<ZyDisYbSrgry> disYbSrgries = dao.selectSurgeries(apply.getPatNo(), apply.getTimes());

        for (ZyInYbDiag itm : inYbDiags) {
            itm.setOperName(userCache.getEmployeeName(itm.getOperId()));
        }
        for (ZyDisYbDiag itm : disYbDiags) {
            itm.setOpName(userCache.getEmployeeName(itm.getOpIdCode()));
            itm.setSsfz(csfrntSrvc.fetchSsfz(itm.getDisDiag(), apply.getPatNo(), apply.getTimes()).getData());
        }
        for (ZyDisYbSrgry itm : disYbSrgries) {
            itm.setSsysName(userCache.getEmployeeName(itm.getSsys()));
            itm.setSszs1Name(userCache.getEmployeeName(itm.getSszs1()));
            itm.setSszs2Name(userCache.getEmployeeName(itm.getSszs2()));
            itm.setMzysName(userCache.getEmployeeName(itm.getMzys()));
        }
        if (param.getInOutFlag() == 1 && DecimalUtil.compare(apply.getDetailTotalCharge(), apply.getLedgerTotalCharge()) != 0) {
            ptntSrvc.receiveAndRecalculateCost(patient);
            SiSettleApply chrgs = dao.selectTotalChargeAgain(apply);
            apply.setDetailTotalCharge(chrgs.getDetailTotalCharge());
            apply.setLedgerTotalCharge(chrgs.getLedgerTotalCharge());
        }
        apply.setFundpayPercentage(DecimalUtil.percentage(apply.getFundpay(), apply.getMedinsTotalCharge()));
        Map<String, Object> map = new HashMap<>();
        map.put("apply", apply);
        map.put("patient", patient);
        map.put("indiags", inYbDiags);
        map.put("disdiags", disYbDiags);
        map.put("surgeries", disYbSrgries);
        if (param.getInOutFlag() == 2) {
            return ResultVoUtil.success(map);
        }
        String message = "";
        if (DecimalUtil.compare(apply.getDetailTotalCharge(), apply.getMedinsTotalCharge()) != 0) {
            message += "此患者明细总费用与医保上传总费用不一致；";
        }
        if (disYbDiags.isEmpty()) {
            message += "此患者没有出院诊断。";
        }
        String ybGender = dao.selectYbGender(apply.getPatNo(), apply.getTimes(), apply.getLedgerSn());
        if (StringUtil.notBlank(ybGender) && !ybGender.equals(String.valueOf(param.getGender()))) {
            message += "此患者医保性别与HIS信息不一致。";
        }
        if (!message.isEmpty()) {
            map.put("warning", message);
        }
        return ResultVoUtil.success(map);
    }

    public ResultVo<String> handleApply(SiSettleApply apply) {
        if (StringUtil.isBlank(apply.getHandleComment())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "处理意见不能为空！");
        }
        apply.setHandleStaff(TokenUtil.getInstance().getTokenUserId());
        dao.handleApply(apply);
        return ResultVoUtil.success("处理成功。");
    }

    public ResultVo<List<SiSettleApply>> selectApplyHistories(SiSettleApply apply) {
        List<SiSettleApply> list = dao.selectApplyHistories(apply);
        list.forEach(item -> item.setHandleStaffName(userCache.getEmployeeName(item.getHandleStaff())));
        return ResultVoUtil.success(list);
    }

    public ResultVo<List<SiSettleApply>> selectSettledApplies(SettledApplyInquiry inquiry) {
        String start = inquiry.getStart() + " 00:00:00";
        String end = inquiry.getEnd() + " 23:59:59";
        List<SiSettleApply> list = dao.selectSettledApplies(start, end);
        if (list.isEmpty()) {
            return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST);
        }
        list.forEach(item -> item.setHandleStaffName(userCache.getEmployeeName(item.getHandleStaff())));
        return ResultVoUtil.success(list);
    }
}
