package thyyxxk.webserver.service.zhuyuanyisheng;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.constants.Message;
import thyyxxk.webserver.dao.his.zhuyuanyisheng.PatientCriticalValuesDao;
import thyyxxk.webserver.entity.ResultVo;
import thyyxxk.webserver.entity.criticalValue.CriticalValue;
import thyyxxk.webserver.entity.criticalValue.InspectionType;
import thyyxxk.webserver.api.medicallaboratory.model.PatientType;
import thyyxxk.webserver.entity.criticalValue.SimpleEmployee;
import thyyxxk.webserver.entity.criticalValue.request.CriticalValueFromTest;
import thyyxxk.webserver.entity.dictionary.CodeName;
import thyyxxk.webserver.http.websocket.SocketV2;
import thyyxxk.webserver.http.websocket.dto.WebSocketByListUserCode;
import thyyxxk.webserver.service.outpatient.wxapi.SendWxInfoService;
import thyyxxk.webserver.utils.*;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class PatientCriticalValuesService {
    private final PatientCriticalValuesDao dao;
    private final SendWxInfoService wxInfoService;
    private final SocketV2 intergrationPlatformSocket;
    private final RestTemplate template;

    public ResultVo<String> acceptCriticalValues(String message) {
        log.info("收到检验危急值消息：{}", message);
        CriticalValue criticalValue = makeEntityFromMessage(message);
        if (StringUtil.isBlank(criticalValue.getContent())) {
            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "消息体为空。");
        }
        if (StringUtil.isBlank(criticalValue.getTargetDeptCode())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "目标科室为空。");
        }
        if (StringUtil.isBlank(criticalValue.getPatNo())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有住院号或门诊号。");
        }
        dao.insertCriticalValue(criticalValue);
        sendMessageToDoctors(criticalValue);
        return ResultVoUtil.success();
    }

    private void sendMessageToDoctors(CriticalValue criticalValue) {
        List<SimpleEmployee> employeeList = getTargetEmployees(criticalValue);
        List<String> codeList = new ArrayList<>();
        StringBuilder codeRsBuilder = new StringBuilder();
        for (SimpleEmployee employee : employeeList) {
            codeList.add(employee.getCode());
            codeRsBuilder.append("|").append(employee.getCodeRs());
        }
        String touser = codeRsBuilder.substring(1);
        String wxMessage = criticalValue.getContent() +
                           "<a href=\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=wwf0b23c8b36012b34&redirect_uri=https://emr.hnthyy.cn/handleCriticalValue?id="
                           + criticalValue.getId()
                           + "&response_type=code&scope=snsapi_privateinfo&state=STATE&agentid=1000052#wechat_redirect\">点击更新危急值状态</a>";
        int sendWxRes = wxInfoService.sendCriticalValue(touser, wxMessage);
        if (sendWxRes == 0) {
            dao.updateSentState(criticalValue.getId());
        }
        JSONObject socketMessage = new JSONObject();
        socketMessage.put("message", criticalValue.getContent());
        socketMessage.put("id", criticalValue.getId());
        String msg = SocketMsg.socketVo(Message.critical_value, socketMessage);

        intergrationPlatformSocket.sendUserCodeListMessage(
                WebSocketByListUserCode.create(codeList, msg)
        );
    }

    private CriticalValue makeEntityFromMessage(String message) {
        JSONObject originCriticalObject = JSONObject.parseObject(message);
        String msgId = originCriticalObject.getString("MsgID");
        String msgType = originCriticalObject.getString("MsgType");
        String sourceCode = originCriticalObject.getString("SourceCode");
        String sourceName = originCriticalObject.getString("SourceName");
        String targetDeptCode = originCriticalObject.getString("TargetDeptCode");
        String targetDeptName = originCriticalObject.getString("TargetDeptName");
        String content = originCriticalObject.getString("Content");
        String createTime = originCriticalObject.getString("CreateTime");
        String patNo = null;
        PatientType patientType = null;
        String patNoLabel = null;
        if (content.contains("住院号")) {
            patientType = PatientType.INPATIENT;
            patNoLabel = "住院号";
        } else if (content.contains("门诊号")) {
            patientType = PatientType.OUTPATIENT;
            patNoLabel = "门诊号";
        }
        if (null != patNoLabel) {
            patNo = content.substring(content.indexOf(patNoLabel) + 4, content.indexOf(",姓名"));
        }
        return new CriticalValue.Builder().patNo(patNo)
                .msgId(msgId).msgType(msgType).sourceCode(sourceCode).sourceName(sourceName)
                .targetDeptCode(targetDeptCode).targetDeptName(targetDeptName)
                .createTime(DateUtil.parseWithDefaultNowTime(createTime))
                .content(content).patientType(patientType)
                .inspectionType(InspectionType.EXAM).build();
    }

    private List<SimpleEmployee> getTargetEmployees(CriticalValue criticalValue) {
        String zkWard = null;
        String referPhysician = null;
        String consultPhysician = null;
        String deptDirector = null;
        if (criticalValue.getPatientType() == PatientType.INPATIENT) {
            Map<String, String> map = dao.selectZkWardByInpatientNo(criticalValue.getPatNo());
            if (map != null && !map.isEmpty()) {
                zkWard = map.get("zkWard");
                referPhysician = map.get("refer_physician");
                consultPhysician = map.get("consult_physician");
                deptDirector = map.get("dept_director");
            }
        }
        String deptCode = null == zkWard ? criticalValue.getTargetDeptCode() : zkWard;
        List<SimpleEmployee> employeeList = dao.selectEmployeesByDept(deptCode);
        List<String> tempWardCodeList = dao.selectWardListBySmallDept(deptCode);
        for (String ward : tempWardCodeList) {
            List<SimpleEmployee> tempList = dao.selectEmployeesByDept(ward);
            employeeList.addAll(tempList);
        }
        List<String> tempCodeList = new ArrayList<>();
        if (StringUtil.notBlank(referPhysician)) {
            tempCodeList.add(referPhysician);
        }
        if (StringUtil.notBlank(consultPhysician)) {
            tempCodeList.add(consultPhysician);
        }
        if (StringUtil.notBlank(deptDirector)) {
            tempCodeList.add(deptDirector);
        }
        if (!tempCodeList.isEmpty()) {
            employeeList.addAll(dao.selectEmployeesByCodeList(tempCodeList));
        }
        employeeList = employeeList.stream().distinct().collect(Collectors.toList());
        return employeeList;
    }

    public CodeName getTargetDept(CriticalValueFromTest value) {
        if (StringUtil.notBlank(value.getSentByDepartmentCode())
            && StringUtil.notBlank(value.getSentByDepartment())) {
            return new CodeName(value.getSentByDepartmentCode(), value.getSentByDepartment());
        }
        CodeName targetDept = null;
        if (value.getPatientType() == PatientType.INPATIENT) {
            targetDept = dao.selectTargetDept(value.getPatNo());
        }
        if (null == targetDept) {
            if (StringUtil.notBlank(value.getSentByDepartmentCode())) {
                targetDept = dao.selectTargetDeptByCode(value.getSentByDepartmentCode());
            } else {
                targetDept = dao.selectTargetDeptByName(value.getSentByDepartment());
            }
        }
        return targetDept;
    }

    public ResultVo<String> checkTheCriticalValue(CriticalValueFromTest value) {
        log.info("收到检查危急值消息：{}", JSON.toJSON(value));
        if (StringUtil.isBlank(value.getPatNo())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "住院/门诊号不能为空。");
        }
        if (null == value.getFlag()) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR,
                    "门诊住院标志[flag]不存在（1=住院，2=门诊）。");
        }
        if (1 != value.getFlag() && 2 != value.getFlag()) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR,
                    "门诊住院标志[flag=" + value.getFlag() + "]值域错误（1=住院，2=门诊）。");
        }
        if (StringUtil.isBlank(value.getSentByDepartment()) && StringUtil.isBlank(value.getSentByDepartmentCode())) {
            return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "送检科室不能为空。");
        }
        PatientType patientType = value.getFlag() == 1 ? PatientType.INPATIENT : PatientType.OUTPATIENT;
        value.setPatientType(patientType);
        CodeName targetDept = getTargetDept(value);
        if (null == targetDept) {
            return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "无法找到患者的送检科室。");
        }

        String label = patientType == PatientType.INPATIENT ? "住院号" : "门诊号";
        if (StringUtil.isBlank(value.getBednum())) {
            value.setBednum("无");
        }
        String message = StrUtil.format("在【{}】就诊患者 【{}：{}，姓名：{}，性别：{}，" +
                                        "年龄：{}，床号：{}】的【{}】检查结果出现危急值情况--【{}】。报告者：{}，" +
                                        "来自：【{}】。",
                targetDept.getName(), label, value.getPatNo(), value.getPatientName(),
                value.getPatientSex(), value.getPatientAge(), value.getBednum(),
                value.getReqName(), value.getMessage(), value.getCommitman(),
                value.getRoomcood());

        String msgId = UUID.randomUUID().toString().replaceAll("-", "");

        CriticalValue criticalValue = new CriticalValue.Builder()
                .patNo(value.getPatNo()).msgId(msgId)
                .msgType("dept_critical_msg")
                .sourceCode(value.getRoomcood())
                .sourceName(value.getRoomcood())
                .targetDeptCode(targetDept.getCode())
                .targetDeptName(targetDept.getName())
                .content(message).createTime(new Date())
                .inspectionType(InspectionType.TEST)
                .patientType(patientType).build();

        dao.insertCriticalValue(criticalValue);
        sendMessageToDoctors(criticalValue);
        return ResultVoUtil.success();
    }

    public ResultVo<List<CriticalValue>> getCriticalValues(String patNo, Integer id) {
        if (id != null) {
            return ResultVoUtil.success(dao.selectCriticalValuesById(id));
        }
        List<CriticalValue> list;
        if (StringUtil.isBlank(patNo)) {
            list = dao.selectAllInpatientCriticalValues();
        } else {
            list = dao.selectCriticalValuesByPatNo(patNo);
        }
        if (list.isEmpty()) {
            return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST);
        }
        return ResultVoUtil.success(list);
    }

    public ResultVo<List<CriticalValue>> getExportCriticalValues(String label) {
        String[] dateArr = getDateArrByLabel(label);
        List<CriticalValue> list = dao.selectExportInpatientCriticalValues(dateArr[0], dateArr[1]);
        if (list.isEmpty()) {
            return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST);
        }
        return ResultVoUtil.success(list);
    }

    private String[] getDateArrByLabel(String label) {
        String end = DateUtil.formatDate(new Date()) + " 23:59:59";
        String start;
        switch (label) {
            case "1week":
                start = DateUtil.getOffsetDate(-7) + " 00:00:00";
                return new String[]{start, end};
            case "1month":
                start = DateUtil.getOffsetDate(-30) + " 00:00:00";
                return new String[]{start, end};
            case "3months":
                start = DateUtil.getOffsetDate(-90) + " 00:00:00";
                return new String[]{start, end};
            case "6months":
                start = DateUtil.getOffsetDate(-180) + " 00:00:00";
                return new String[]{start, end};
            case "1year":
            default:
                start = DateUtil.getOffsetDate(-365) + " 00:00:00";
                return new String[]{start, end};
        }
    }

    public ResultVo<String> handleZyCriticalValue(Integer id) {
        String handleStaff = TokenUtil.getInstance().getTokenUserId();
        String url = "http://192.168.200.6:8320/hospitalAppsApi/criticalValue/updateState?user=" + handleStaff + "&id=" + id;
        return template.getForObject(url, ResultVo.class);
    }
}
