package thyyxxk.webserver.service.inpatient.casefrontsheet;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.config.exception.ExceptionEnum;
import thyyxxk.webserver.constants.Message;
import thyyxxk.webserver.dao.his.inpatient.casefrontsheet.QualityVerificationDao;
import thyyxxk.webserver.entity.casefrontsheet.CaseFrontsheetMain;
import thyyxxk.webserver.entity.casefrontsheet.pojo.FrontsheetQualityVerification;
import thyyxxk.webserver.entity.casefrontsheet.pojo.GroupLeaderVerification;
import thyyxxk.webserver.entity.casefrontsheet.request.AuditInquiry;
import thyyxxk.webserver.entity.casefrontsheet.response.AuditCount;
import thyyxxk.webserver.entity.casefrontsheet.state.AuditState;
import thyyxxk.webserver.entity.casefrontsheet.state.State;
import thyyxxk.webserver.entity.dictionary.CodeName;
import thyyxxk.webserver.entity.socketmessage.SocketMessage;
import thyyxxk.webserver.service.hutoolcache.UserCache;
import thyyxxk.webserver.http.websocket.SocketV2;
import thyyxxk.webserver.http.websocket.dto.WebSocketByListUserCode;
import thyyxxk.webserver.http.websocket.dto.WebSocketByUserCode;
import thyyxxk.webserver.service.outpatient.wxapi.SendWxInfoService;
import thyyxxk.webserver.utils.ListUtil;
import thyyxxk.webserver.utils.SnowFlakeId;
import thyyxxk.webserver.utils.StringUtil;
import thyyxxk.webserver.utils.TokenUtil;
import thyyxxk.webserver.utils.*;

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

@Slf4j
@Service
public class FrontsheetAuditService {
    private final QualityVerificationDao dao;
    private final SendWxInfoService sendWxInfoService;
    private final CaseFrontSheetMainService sheetService;
    private final UserCache userCache;
    private final SocketV2 intergrationPlatformSocket;

    @Autowired
    public FrontsheetAuditService(QualityVerificationDao dao, SendWxInfoService sendWxInfoService, CaseFrontSheetMainService sheetService, UserCache userCache, SocketV2 intergrationPlatformSocket) {
        this.dao = dao;
        this.sendWxInfoService = sendWxInfoService;
        this.sheetService = sheetService;
        this.userCache = userCache;
        this.intergrationPlatformSocket = intergrationPlatformSocket;
    }

    public String submitQualityVerification(FrontsheetQualityVerification request) {
        QueryWrapper<FrontsheetQualityVerification> wrapper = new QueryWrapper<>();
        wrapper.eq("pat_no", request.getPatNo());
        wrapper.eq("times", request.getTimes());
        wrapper.eq("audit_state", AuditState.INITIAL);
        long exist = dao.selectCount(wrapper);
        if (exist > 0) {
            return "您有已提交的审核申请，请勿重复提交。";
        }
        String tokenUser = TokenUtil.getInstance().getTokenUserId();
        String userName = userCache.getEmployeeName(tokenUser);
        request.setId(SnowFlakeId.instance().nextId());
        request.setDoctorCode(tokenUser);
        request.setDoctorName(userName);
        request.setApplicationTime(new Date());
        int result = dao.insert(request);
        if (result == 1) {
            List<String> auditors = dao.selectAuditors();
            String message = SocketMsg.socketVo(Message.SYSTEM_NOTIFICATION, "有新的病案质控申请。");
            intergrationPlatformSocket.sendUserCodeListMessage(WebSocketByListUserCode.create(auditors, message));
            return "OK";
        }
        return "提交审核失败，请稍后再试。";
    }

    public List<FrontsheetQualityVerification> fetchQualityVerifications(AuditInquiry inquiry) {
        if (inquiry.getState() != AuditState.REJECTED) {
            QueryWrapper<FrontsheetQualityVerification> wrapper = new QueryWrapper<>();
            wrapper.eq("audit_state", inquiry.getState());
            wrapper.ge("application_time", inquiry.getStart());
            wrapper.le("application_time", inquiry.getEnd());
            if (StringUtil.notBlank(inquiry.getPatNo())) {
                wrapper.eq("pat_no", inquiry.getPatNo());
            }
            if (ListUtil.notBlank(inquiry.getDeptList())) {
                wrapper.in("dis_dept_code", inquiry.getDeptList());
            }
            return dao.selectList(wrapper);
        }
        String statement = "";
        if (StringUtil.notBlank(inquiry.getPatNo())) {
            statement = " and pat_no='" + inquiry.getPatNo() + "'";
        }
        if (ListUtil.notBlank(inquiry.getDeptList())) {
            statement += " and dis_dept_code in " + makeInStatement(inquiry.getDeptList());
        }
        return dao.selectRejectedRecords(inquiry.getStart(), inquiry.getEnd(), statement);
    }

    private String makeInStatement(List<String> list) {
        StringBuilder builder = new StringBuilder();
        for (String item : list) {
            builder.append(",'").append(item).append("'");
        }
        builder.append(")");
        return "(" + builder.substring(1);
    }

    public String executeAudit(FrontsheetQualityVerification request) {
        String userCode = TokenUtil.getInstance().getTokenUserId();
        request.setAuditStaffCode(userCode);
        request.setAuditStaffName(userCache.getEmployeeName(userCode));
        request.setAuditTime(new Date());
        request.setMajorError(makeStringOutOfList(request.getMajorErrorList()));
        int result = dao.updateById(request);
        if (result == 1) {
            String message;
            if (request.getAuditState() == AuditState.APPROVED) {
                insertSheetAfterPrint(request.getSheet());
                message = StrUtil.format("【患者：{}({}-{})】病案首页质控审核已通过。",
                        request.getPatName(), request.getPatNo(), request.getTimes());
            } else {
                message = StrUtil.format("【患者：{}({}-{})】病案首页质控审核已驳回。原因：{}",
                        request.getPatName(), request.getPatNo(), request.getTimes(), request.getAuditRemark());
            }

            message = SocketMsg.socketVo(Message.SYSTEM_NOTIFICATION, message);
            intergrationPlatformSocket.sendMessageByUserCode(new WebSocketByUserCode(request.getDoctorCode(), message));

            String codeRs = userCache.get(request.getDoctorCode()).getCodeRs();
            if (StringUtil.notBlank(codeRs)) {
                sendWxInfoService.sendCorpWxMsg(codeRs, message);
            }
            return "OK";
        }
        return "数据库错误，请联系管理员。";
    }

    private void insertSheetAfterPrint(CaseFrontsheetMain sheet) {
        String bah = sheet.getBah();
        int times = sheet.getAdmissTimes();
        Integer fileStatus = dao.selectFileStatus(bah, times);
        if (null == fileStatus || fileStatus == State.FileStatus.UNSIGNED) {
            sheet.setFileStatus(State.FileStatus.UNSIGNED);
            sheetService.insertSheetData(sheet);
        }
    }

    public String revokeApprovedAudit(FrontsheetQualityVerification request) {
        Integer fileStatus = dao.selectFileStatus(request.getPatNo(), request.getTimes());
        if (null != fileStatus && fileStatus == 1) {
            throw new BizException(ExceptionEnum.LOGICAL_ERROR, "病案已签收，无法撤销审核。");
        }
        int result = dao.revokeApprovedAudit(request.getId());
        if (result == 0) {
            throw new BizException("数据库错误，请稍后再试。");
        }
        log.info("操作员：【{}】撤销病案质控已通过的审核：\n{}",
                TokenUtil.getInstance().getTokenUserId(), JSON.toJSONString(request));
        return "撤销成功。";
    }

    public Map<String, Object> fetchAuditHistories(FrontsheetQualityVerification request) {
        QueryWrapper<FrontsheetQualityVerification> wrapper = new QueryWrapper<>();
        wrapper.eq("pat_no", request.getPatNo());
        wrapper.eq("times", request.getTimes());
        wrapper.ne("audit_state", AuditState.INITIAL);
        wrapper.orderByAsc("application_time");
        List<FrontsheetQualityVerification> histories = dao.selectList(wrapper);
        List<GroupLeaderVerification> leaderAudits = dao.fetchGroupLeaderAudit(request.getPatNo(), request.getTimes());
        Map<String, Object> map = new HashMap<>();
        map.put("histories", histories);
        map.put("leaderAudits", leaderAudits);
        return map;
    }

    public AuditCount fetchAuditCount(FrontsheetQualityVerification request) {
        AuditCount auditCount = new AuditCount();
        QueryWrapper<FrontsheetQualityVerification> wrapper = new QueryWrapper<>();
        wrapper.eq("pat_no", request.getPatNo());
        wrapper.eq("times", request.getTimes());
        wrapper.eq("audit_state", AuditState.INITIAL);
        auditCount.setInitial(dao.selectCount(wrapper));

        wrapper = new QueryWrapper<>();
        wrapper.eq("pat_no", request.getPatNo());
        wrapper.eq("times", request.getTimes());
        wrapper.eq("audit_state", AuditState.APPROVED);
        auditCount.setApproved(dao.selectCount(wrapper));

        wrapper = new QueryWrapper<>();
        wrapper.eq("pat_no", request.getPatNo());
        wrapper.eq("times", request.getTimes());
        wrapper.eq("audit_state", AuditState.REJECTED);
        auditCount.setRejected(dao.selectCount(wrapper));
        return auditCount;
    }

    public List<CodeName> getAllSmallDept() {
        return dao.selectAllSmallDeptWithInpatientFlag();
    }

    public List<FrontsheetQualityVerification> fetchExportData(AuditInquiry inquiry) {
        QueryWrapper<FrontsheetQualityVerification> wrapper = new QueryWrapper<>();
        wrapper.ge("audit_time", inquiry.getStart());
        wrapper.le("audit_time", inquiry.getEnd());
        wrapper.orderByAsc("pat_no,times,audit_time");
        return dao.selectList(wrapper);
    }

    private String makeStringOutOfList(List<String> list) {
        if (null == list || list.isEmpty()) {
            return null;
        }
        StringBuilder builder = new StringBuilder();
        for (String item : list) {
            builder.append("，").append(item);
        }
        return builder.substring(1);
    }

    public List<GroupLeaderVerification> fetchLeaderAudit(AuditInquiry inquiry) {
        return dao.fetchGroupLeaderAudit(inquiry.getPatNo(), inquiry.getTimes());
    }

    public String submitLeaderAudit(GroupLeaderVerification request) {
        request.setId(SnowFlakeId.instance().nextId());
        String auditCode = TokenUtil.getInstance().getTokenUserId();
        String auditName = userCache.getEmployeeName(auditCode);
        request.setAuditCode(auditCode);
        request.setAuditName(auditName);
        request.setMajorError(makeStringOutOfList(request.getMajorErrorList()));
        if (request.getAuditState() == AuditState.APPROVED
            && StringUtil.isBlank(request.getAuditRemark())) {
            request.setAuditRemark("审核通过");
        }
        dao.insertLeaderAudit(request);
        if (request.getAuditState() == AuditState.REJECTED) {
            String patId = request.getPatNo() + "-" + request.getTimes();
            String message = "患者 " + request.getPatName() + "（" + patId + "）编码组长审核未通过。";

            SocketMessage socketMessage = new SocketMessage();
            socketMessage.setId(SnowFlakeId.instance().nextId());
            socketMessage.setLevel(0);
            socketMessage.setSender(auditCode);
            socketMessage.setTitle("编码组长审核不通过");
            socketMessage.setContent(message);
            socketMessage.setPatId(patId);
            dao.insertNewMessage(socketMessage);

            JSONObject messageWrapper = new JSONObject();
            messageWrapper.put("name", "systemNotification");
            JSONObject messageBody = new JSONObject();
            messageBody.put("title", "提示");
            messageBody.put("message", message);
            messageWrapper.put("message", messageBody);

            WebSocketByUserCode webSocketByUserCode = new WebSocketByUserCode();
            webSocketByUserCode.setMessage(messageWrapper);

            String[] coder = request.getCoderCode().split("，");

            List<SocketMessage> socketMessageList = new ArrayList<>();
            for (int i = 0; i < coder.length; i++) {
                String userCode = coder[i];
                SocketMessage consumerMessage = new SocketMessage();
                consumerMessage.setMsgId(socketMessage.getId());
                consumerMessage.setSender(auditCode);
                consumerMessage.setReceiver(userCode);
                socketMessageList.add(consumerMessage);
                webSocketByUserCode.setSid(userCode);

                intergrationPlatformSocket.sendMessageByUserCode(webSocketByUserCode);

                if (i != coder.length - 1) {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            dao.insertMessageConsumer(socketMessageList);
        }
        return request.getId();
    }

    public List<GroupLeaderVerification> fetchLeaderExportData(AuditInquiry inquiry) {
        return dao.fetchLeaderExportData(inquiry.getStart(), inquiry.getEnd());
    }
}
