package thyyxxk.webserver.controller.medicalinsurance;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import thyyxxk.webserver.config.exception.BizException;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.constants.sidicts.MedType;
import thyyxxk.webserver.constants.sidicts.SiFunction;
import thyyxxk.webserver.dao.his.inpatient.DoctorsAdviseDao;
import thyyxxk.webserver.dao.his.medicalinsurance.EmergencyRescueDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.dictionary.CodeName;
import thyyxxk.webserver.entity.medicalinsurance.inpatient.FeeDtle;
import thyyxxk.webserver.entity.medicalinsurance.inpatient.SiChargeTemp;
import thyyxxk.webserver.entity.medicalinsurance.inpatient.ZyPatientInfo;
import thyyxxk.webserver.entity.medicalinsurance.outpatient.MzPatientInfo;
import thyyxxk.webserver.http.websocket.dto.WebSocketByUserCode;
import thyyxxk.webserver.http.websocket.SocketV2;
import thyyxxk.webserver.service.medicalinsurance.ExecService;
import thyyxxk.webserver.service.medicalinsurance.SiZyService;
import thyyxxk.webserver.service.medicalinsurance.impl.JzYbData;
import thyyxxk.webserver.utils.ResultVoUtil;
import thyyxxk.webserver.utils.StringUtil;
import thyyxxk.webserver.utils.TokenUtil;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping("/emergencyRescue")
public class EmergencyRescueController {
    private static final String RESULT_CODE = "infcode";
    private static final String ERROR_MESSAGE = "err_msg";
    private static final String OUTPUT = "output";

    private final EmergencyRescueDao dao;
    private final DoctorsAdviseDao doctorsAdviseDao;
    private final SiZyService zyService;
    private final JzYbData jzYbData;
    private final SocketV2 socketService;
    private final ExecService execService;

    @Autowired
    public EmergencyRescueController(EmergencyRescueDao dao, SiZyService zyService, JzYbData jzYbData, SocketV2 socketService, ExecService execService, DoctorsAdviseDao doctorsAdviseDao) {
        this.dao = dao;
        this.doctorsAdviseDao = doctorsAdviseDao;
        this.zyService = zyService;
        this.jzYbData = jzYbData;
        this.socketService = socketService;
        this.execService = execService;
    }

    @PostMapping("/checkGeneratedFees")
    public ResultVo<Integer> checkGeneratedFees(@RequestBody MzPatientInfo mzptnt) {
        int feeCount = dao.checkGeneratedFees(mzptnt);
        if (feeCount > 0) {
            return ResultVoUtil.success(feeCount);
        }
        return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "请先生成医保费用！");
    }

    @PostMapping("/executeEmergencyRescue")
    public ResultVo<String> executeEmergencyRescue(@RequestBody MzPatientInfo mzptnt) throws Exception {
        String userCode = TokenUtil.getInstance().getTokenUserId();
        mzptnt.setStaffId(userCode);
        mzptnt.setMedType(MedType.GENERAL_HOSPITALIZATION.getCode());

        if (StringUtil.isBlank(mzptnt.getSocialNo())) {
            mzptnt.setSocialNo(dao.getMzSocialNo(mzptnt.getPatNo()));
        }

        WebSocketByUserCode socketBody = new WebSocketByUserCode();
        socketBody.setSid(userCode);

        JSONObject msgdata = new JSONObject();
        msgdata.put("code", "emergencyRescueProcess");
        msgdata.put("message", "正在办理住院登记...");
        socketBody.setMessage(msgdata);
        socketService.sendMessageByUserCode(socketBody);
        TimeUnit.MILLISECONDS.sleep(200);

        ZyPatientInfo jzptnt = makeJzptnt(mzptnt);
        String message = zyService.admissRegister(jzptnt, jzYbData);

        msgdata.replace("message", message);
        socketBody.setMessage(msgdata);
        socketService.sendMessageByUserCode(socketBody);
        TimeUnit.MILLISECONDS.sleep(200);

        msgdata.replace("message", "正在上传费用...");
        socketBody.setMessage(msgdata);
        socketService.sendMessageByUserCode(socketBody);
        TimeUnit.MILLISECONDS.sleep(200);

        message = uploadFees(mzptnt);
        msgdata.replace("message", message);
        socketBody.setMessage(msgdata);
        socketService.sendMessageByUserCode(socketBody);
        TimeUnit.MILLISECONDS.sleep(200);

        message = zyService.hospitalizationPreSettlement(jzptnt, jzYbData);
        msgdata.replace("message", "试算成功。" + message);
        socketBody.setMessage(msgdata);
        socketService.sendMessageByUserCode(socketBody);
        TimeUnit.MILLISECONDS.sleep(200);

        msgdata.replace("message", "正在办理出院结算...");
        socketBody.setMessage(msgdata);
        socketService.sendMessageByUserCode(socketBody);

        TimeUnit.MILLISECONDS.sleep(200);
        message = zyService.dischargeProcessing(jzptnt, jzYbData);
        return ResultVoUtil.success(message);
    }

    private ZyPatientInfo makeJzptnt(MzPatientInfo mzptnt) {
        ZyPatientInfo jzptnt = new ZyPatientInfo();
        jzptnt.setInpatientNo(mzptnt.getPatNo());
        jzptnt.setAdmissTimes(mzptnt.getTimes());
        jzptnt.setLedgerSn(0);
        jzptnt.setMedType(mzptnt.getMedType());
        jzptnt.setInsutype(mzptnt.getInsutype());
        jzptnt.setInsuplcAdmdvs(mzptnt.getInsuplcAdmdvs());
        jzptnt.setInsuplcAdmdvsName(mzptnt.getInsuplcAdmdvsName());
        jzptnt.setStaffId(mzptnt.getStaffId());
        jzptnt.setMdtrtCertType(mzptnt.getMdtrtCertType());
        jzptnt.setReadCardBizType(mzptnt.getReadCardBizType());
        jzptnt.setReadCardResult(mzptnt.getReadCardResult());
        jzptnt.setSocialNo(mzptnt.getSocialNo());
        return jzptnt;
    }

    private String uploadFees(MzPatientInfo mzptnt) {
        CodeName caty = dao.getSiCaty(mzptnt.getPatNo(), mzptnt.getTimes());
        if (null == caty || StringUtil.isBlank(caty.getCode())) {
            throw new BizException("就诊科室未匹配医保字典。");
        }
        List<FeeDtle> feeList = dao.getFeeList(mzptnt.getPatNo(), mzptnt.getTimes());
        if (feeList.isEmpty()) {
            throw new BizException("没有可以上传的费用。");
        }
        feeList.forEach(item -> {
            item.setBilgDeptCodg(caty.getCode());
            item.setBilgDeptName(caty.getName());
            item.setOrdersDrCode(item.getBilgDrCodg());
            item.setOrdersDrName(item.getBilgDrName());
            item.setMedType(mzptnt.getMedType());
        });
        JSONObject input = execService.makeTradeHeaderWithInsureArea(SiFunction.UPLOAD_HOSPITALIZATION_FEE_DETAILS, mzptnt.getInsuplcAdmdvs());
        return uploadBatchFees(feeList, mzptnt, input);
    }

    private String uploadBatchFees(List<FeeDtle> feeList, MzPatientInfo mzptnt, JSONObject input) {
        String result = "";
        List<FeeDtle> tempList = new ArrayList<>();
        for (FeeDtle feeDtl : feeList) {
            // 当医生有医保姓名时，优先使用医保姓名
            try {
                String ybName = doctorsAdviseDao.getYbName(feeDtl.getBilgDrCodg());
                if(StringUtil.isNotEmpty(ybName)) {
                    log.info("住院费用上传医生{}，使用医保姓名：{}", feeDtl.getBilgDrName(), ybName);
                    feeDtl.setBilgDrName(ybName);
                }
            } catch (Exception e) {
                log.error(e.getMessage());
                log.error("获取医保姓名出错：{}", feeDtl.getBilgDrCodg());
            }
            tempList.add(feeDtl);
            if (tempList.size() == 100) {
                result = executeUploadFees(input, tempList, mzptnt);
                tempList.clear();
            }
        }
        if (!tempList.isEmpty()) {
            result = executeUploadFees(input, tempList, mzptnt);
        }
        return result;
    }

    private String executeUploadFees(JSONObject input, List<FeeDtle> fees, MzPatientInfo p) {
        String ref = JSONArray.toJSONString(fees);
        input.getJSONObject("input").put("feedetail", JSONArray.parse(ref));
        JSONObject result = execService.executeTrade(input, SiFunction.UPLOAD_HOSPITALIZATION_FEE_DETAILS);
        if (null == result) {
            throw new BizException("医保网络异常。");
        }
        if (result.getIntValue(RESULT_CODE) != 0) {
            throw new BizException(ExceptionEnum.LOGICAL_ERROR, result.getString(ERROR_MESSAGE));
        }
        JSONArray array = result.getJSONObject(OUTPUT).getJSONArray("result");
        List<SiChargeTemp> tempList = new ArrayList<>();
        for (int i = 0; i < array.size(); i++) {
            JSONObject upldretrn = array.getJSONObject(i);
            SiChargeTemp chrgtemp = JSONObject.parseObject(upldretrn.toJSONString(), SiChargeTemp.class);
            chrgtemp.setPatNo(p.getPatNo());
            chrgtemp.setTimes(p.getTimes());
            tempList.add(chrgtemp);
        }
        dao.updateTransFlag(p.getPatNo(), p.getTimes(), tempList);
        return "费用上传完成。";
    }

    @PostMapping("/revokeBusiness")
    public ResultVo<String> revokeBusiness(@RequestBody MzPatientInfo mzptnt) throws InterruptedException {
        String userCode = TokenUtil.getInstance().getTokenUserId();
        mzptnt.setStaffId(userCode);

        WebSocketByUserCode socketBody = new WebSocketByUserCode();
        socketBody.setSid(userCode);

        JSONObject msgdata = new JSONObject();
        msgdata.put("code", "emergencyRescueProcess");
        msgdata.put("message", "正在尝试撤销医保结算...");
        socketBody.setMessage(msgdata);
        socketService.sendMessageByUserCode(socketBody);
        TimeUnit.MILLISECONDS.sleep(200);

        ZyPatientInfo jzptnt = makeJzptnt(mzptnt);
        String rvkSetlResult;
        try {
            rvkSetlResult = zyService.revokeSettlement(jzptnt);
        } catch (BizException e) {
            rvkSetlResult = e.getMessage();
        }
        msgdata.replace("message", rvkSetlResult);
        socketBody.setMessage(msgdata);
        socketService.sendMessageByUserCode(socketBody);
        TimeUnit.MILLISECONDS.sleep(200);

        msgdata.replace("message", "正在尝试撤销已上传的费用...");
        socketBody.setMessage(msgdata);
        socketService.sendMessageByUserCode(socketBody);
        TimeUnit.MILLISECONDS.sleep(200);

        String rvkUploadResult;
        try {
            rvkUploadResult = zyService.revokeUploadFees(jzptnt);
        } catch (BizException e) {
            rvkUploadResult = e.getMessage();
        }
        msgdata.replace("message", rvkUploadResult);
        socketBody.setMessage(msgdata);
        socketService.sendMessageByUserCode(socketBody);
        TimeUnit.MILLISECONDS.sleep(200);

        msgdata.replace("message", "正在尝试撤销医保登记...");
        socketBody.setMessage(msgdata);
        socketService.sendMessageByUserCode(socketBody);
        TimeUnit.MILLISECONDS.sleep(200);

        String rvkRegister;
        try {
            rvkRegister = zyService.revokeAdmission(jzptnt);
        } catch (BizException e) {
            rvkRegister = e.getMessage();
        }
        return ResultVoUtil.success(rvkRegister);
    }
}
