package com.supervision.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.supervision.exception.BusinessException;
import com.supervision.model.*;
import com.supervision.model.Process;
import com.supervision.pojo.vo.*;
import com.supervision.service.*;
import com.supervision.vo.manage.DiseaseTreatmentPlanResVo;
import com.supervision.vo.result.AncillaryRecordByResultDAO;
import com.supervision.vo.result.PhysicalRecordByResultDAO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class AskDiagnosisResultServiceImpl implements AskDiagnosisResultService {

    private final DiagnosisResultService diagnosisResultService;

    private final DiagnosisPrimaryService diagnosisPrimaryService;

    private final AskPatientAnswerService askPatientAnswerService;

    private final MedicalRecService medicalRecService;

    private final DiagnosisQaRecordService diagnosisQaRecordService;

    private final DiagnosisPhysicalRecordService diagnosisPhysicalRecordService;

    private final DiagnosisAncillaryRecordService diagnosisAncillaryRecordService;

    private final ProcessService processService;

    private final PatientService patientService;

    private final DiseaseService diseaseService;

    private final TreatmentPlanRecordService treatmentPlanRecordService;

    private final  DiseaseTreatmentPlanService diseaseTreatmentPlanService;


    private final DiseaseTreatmentPlanDrugService diseaseTreatmentPlanDrugService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void finishAsk(FinishAskReqVO reqVO) {
        // 首先保存诊断结果
        DiagnosisResult diagnosisResult = new DiagnosisResult();
        diagnosisResult.setProcessId(reqVO.getProcessId());
        // 最终诊断结果,从初步诊断中获取
        List<DiagnosisPrimary> list = diagnosisPrimaryService.lambdaQuery()
                .eq(DiagnosisPrimary::getProcessId, reqVO.getProcessId())
                .eq(DiagnosisPrimary::getExcludeFlag,0)
                .list();
        if (CollectionUtil.isEmpty(list)){
            throw new BusinessException("您还未进行有效的初步诊断!");
        }
        diagnosisResult.setFinalDiagnosis(list.stream().map(DiagnosisPrimary::getPrimaryDiagnosisId).collect(Collectors.toList()));
        diagnosisResult.setTreatmentPlanType(reqVO.getTreatmentPlanType());
        diagnosisResult.setTreatmentPlan(reqVO.getTreatmentPlan());
        diagnosisResultService.save(diagnosisResult);

        // todo:修改流程状态
    }

    @Override
    public DiagnosisResultResVO queryDiagnosisResult(String processId) {
        // 首先查询到结果
        DiagnosisResult diagnosisResult = diagnosisResultService.lambdaQuery()
                .eq(DiagnosisResult::getProcessId, processId).last("limit 1").oneOpt().orElseThrow(() -> new BusinessException("未找到评估结果"));
        DiagnosisResultResVO diagnosisResultResVO = new DiagnosisResultResVO();
        diagnosisResultResVO.setId(processId);
        Process process = processService.getById(processId);
        Patient patient = patientService.getById(process.getPatientId());
        MedicalRec medicalRec = medicalRecService.getById(process.getMedicalRecId());
        List<Disease> diseasesList = diseaseService.listDiseaseWithType(medicalRec.getDiseaseId());
        // 1.生成预期诊断结果
        diagnosisResultResVO.setExpertDiagnosisResult(creatExpertDiagnosisResult(medicalRec, diagnosisResult, diseasesList));
        // 2.生成初步诊断依据
        diagnosisResultResVO.setBasisPrimaryResultResVO(createBasisPrimaryResult(patient, processId, diseasesList));
        // 3.生成证实诊断依据
        diagnosisResultResVO.setBasisConfirmResultResVO(createBasisConfirmResult(processId, diseasesList));
        // 4.生成鉴别诊断依据
        diagnosisResultResVO.setBasisIdentificationResult(createBasisIdentificationResult(processId, diseasesList));
        // 5.全面检查-(暂无相关数据) 后面再看
        diagnosisResultResVO.setFullCheck(null);
        // 6.处置方案
        diagnosisResultResVO.setDealPlan(createDealPlan(process.getDiseaseId(), processId));
        return diagnosisResultResVO;
    }

    private DealPlanResVO createDealPlan(String diseaseId, String processId) {

        DealPlanResVO dealPlanResVO = new DealPlanResVO();

        // 1. 查询处置计划记录
        List<TreatmentPlanRecord> treatmentPlanRecordList = treatmentPlanRecordService.lambdaQuery().eq(TreatmentPlanRecord::getProcessId, processId).list();
        if (CollectionUtil.isEmpty(treatmentPlanRecordList)){
            return dealPlanResVO;
        }

        // 2. 查询出疾病处置计划
        List<DiseaseTreatmentPlanResVo> diseaseTreatmentPlanResVos = diseaseTreatmentPlanService.queryListByDiseaseId(diseaseId);
        List<String> planIds = diseaseTreatmentPlanResVos.stream().map(DiseaseTreatmentPlanResVo::getPlanId).distinct().collect(Collectors.toList());

        // 3. 查出疾病处置计划用药
        List<DiseaseTreatmentPlanDrug> diseaseTreatmentPlanDrugList = diseaseTreatmentPlanDrugService.lambdaQuery().eq(DiseaseTreatmentPlanDrug::getDiseaseId, diseaseId).list();
        List<String> drugIds = diseaseTreatmentPlanDrugList.stream().map(DiseaseTreatmentPlanDrug::getDrugId).distinct().collect(Collectors.toList());

        // 4. 组装数据
        ArrayList<DealPlanResVO.TreatmentPlanResult> drugTreatmentPlanResults = new ArrayList<>();
        ArrayList<DealPlanResVO.TreatmentPlanResult> otherTreatmentPlanResults = new ArrayList<>();
        for (TreatmentPlanRecord treatmentPlanRecord : treatmentPlanRecordList) {
            DealPlanResVO.TreatmentPlanResult bean = BeanUtil.toBean(treatmentPlanRecord, DealPlanResVO.TreatmentPlanResult.class);
            boolean flag = bean.getDisposalPlan().equals(1) ? drugIds.contains(bean.getDrugId()) : planIds.contains(bean.getTreatmentPlanId());
            bean.setFlag(flag ? 1 : 0);
            if (bean.getDisposalPlan().equals(1)){
                drugTreatmentPlanResults.add(bean);
            }else {
                otherTreatmentPlanResults.add(bean);
            }

        }
        dealPlanResVO.setUserTreatmentPlanType(CollectionUtil.getFirst(treatmentPlanRecordList).getDisposalMethod());
        dealPlanResVO.setDrugTreatmentPlan(drugTreatmentPlanResults);
        dealPlanResVO.setOtherTreatmentPlan(otherTreatmentPlanResults.stream().sorted(
                Comparator.comparing(TreatmentPlanRecord::getDisposalPlan)).collect(Collectors.toList()));
        return dealPlanResVO;

    }

    private BasisIdentificationResultResVO createBasisIdentificationResult(String processId, List<Disease> diseasesList) {
        BasisIdentificationResultResVO basisIdentificationResultResVO = new BasisIdentificationResultResVO();
        // todo : 由于修改了表结构,导致证实依据字段不存在。。。
        basisIdentificationResultResVO.setIdentificationDiagnosis(diseasesList.stream().map(e->"").collect(Collectors.toList()));
        // 2.2 获取体格检查
        List<PhysicalRecordByResultDAO> physicalRecordList = diagnosisPhysicalRecordService.queryPhysicalResultByProcessId(processId);
        List<BasisDiagnosisNodeResVO> nodeList = physicalRecordList.stream()
                .filter(distinctPredicateNotNull(PhysicalRecordByResultDAO::getToolLocationName)).map(e -> {
            BasisDiagnosisNodeResVO nodeResVO = new BasisDiagnosisNodeResVO();
            nodeResVO.setType(1);
            nodeResVO.setRecordName(e.getToolLocationName());
            nodeResVO.setRecordId(e.getRecordId());
            // 如果是必做的,则是正确
            nodeResVO.setCorrect(null == e.getBasisIdentification() ? Integer.valueOf(0) : e.getBasisIdentification());
            return nodeResVO;
        }).collect(Collectors.toList());
        // 2.3 获取辅助检查
        List<AncillaryRecordByResultDAO> ancillaryRecordList = diagnosisAncillaryRecordService.queryAncillaryResultByProcessId(processId);
        List<BasisDiagnosisNodeResVO> collect = ancillaryRecordList.stream()
                .filter(distinctPredicateNotNull(AncillaryRecordByResultDAO::getItemName)).map(e -> {
            BasisDiagnosisNodeResVO nodeResVO = new BasisDiagnosisNodeResVO();
            nodeResVO.setCorrect(null == e.getBasisIdentification() ? Integer.valueOf(0) : e.getBasisIdentification());
            nodeResVO.setRecordId(e.getRecordId());
            nodeResVO.setRecordName(e.getItemName());
            nodeResVO.setType(2);
            return nodeResVO;
        }).collect(Collectors.toList());
        nodeList.addAll(collect);

        basisIdentificationResultResVO.setNodeList(nodeList);
        return basisIdentificationResultResVO;
    }

    private BasisConfirmResultResVO createBasisConfirmResult(String processId, List<Disease> diseasesList) {
        BasisConfirmResultResVO basisConfirmResultResVO = new BasisConfirmResultResVO();
        //todo: 由于修改了表结构,导致证实依据不存在....
        basisConfirmResultResVO.setConfirmingDiagnosis(diseasesList.stream().map(e->"").collect(Collectors.toList()));
        // 2.2 获取体格检查
        List<PhysicalRecordByResultDAO> physicalRecordList = diagnosisPhysicalRecordService.queryPhysicalResultByProcessId(processId);
        List<BasisDiagnosisNodeResVO> nodeList = physicalRecordList.stream()
                .filter(distinctPredicateNotNull(PhysicalRecordByResultDAO::getToolLocationName)).map(e -> {
            BasisDiagnosisNodeResVO nodeResVO = new BasisDiagnosisNodeResVO();
            nodeResVO.setType(1);
            nodeResVO.setRecordName(e.getToolLocationName());
            nodeResVO.setRecordId(e.getRecordId());
            // 如果是必做的,则是正确
            nodeResVO.setCorrect(null == e.getBasisConfirm() ? Integer.valueOf(0) : e.getBasisConfirm());
            return nodeResVO;
        }).collect(Collectors.toList());
        // 2.3 获取辅助检查
        List<AncillaryRecordByResultDAO> ancillaryRecordList = diagnosisAncillaryRecordService.queryAncillaryResultByProcessId(processId);
        List<BasisDiagnosisNodeResVO> collect = ancillaryRecordList.stream()
                .filter(distinctPredicateNotNull(AncillaryRecordByResultDAO::getItemName)).map(e -> {
            BasisDiagnosisNodeResVO nodeResVO = new BasisDiagnosisNodeResVO();
            nodeResVO.setCorrect(null == e.getBasisConfirm() ? Integer.valueOf(0) : e.getBasisConfirm());
            nodeResVO.setRecordId(e.getRecordId());
            nodeResVO.setRecordName(e.getItemName());
            nodeResVO.setType(2);
            return nodeResVO;
        }).collect(Collectors.toList());
        nodeList.addAll(collect);

        basisConfirmResultResVO.setNodeList(nodeList);
        return basisConfirmResultResVO;
    }

    private BasisPrimaryResultResVO createBasisPrimaryResult(Patient patient, String processId, List<Disease> diseasesList) {
        BasisPrimaryResultResVO basisPrimaryResultResVO = new BasisPrimaryResultResVO();
        //todo: 由于修改了表结构导致初步诊断不存在
        basisPrimaryResultResVO.setPreliminaryDiagnosis(diseasesList.stream().map(e->"").collect(Collectors.toList()));
        // 根据record记录寻找符合初步诊断依据的项目
        // 2.1 首先获取对话
        List<BasisDiagnosisNodeResVO> basisDiagnosisNodeResVOS = new ArrayList<>();
        List<DiagnosisQaRecord> qaRecordList = diagnosisQaRecordService.lambdaQuery().eq(DiagnosisQaRecord::getProcessId, processId).list();
        if (CollectionUtil.isNotEmpty(qaRecordList)) {
            List<AskPatientAnswer> list = askPatientAnswerService.lambdaQuery()
                    .eq(AskPatientAnswer::getPatientId, patient.getId()).list();
            // 获取配置了答案的项目(配置了答案的,认为是正确,没有配置答案的,走默认回答的,不标记为以正确)
            Set<String> requireCheckIdSet = list.stream().map(AskPatientAnswer::getId).collect(Collectors.toSet());
            List<BasisDiagnosisNodeResVO> qaList = qaRecordList.stream().map(e -> {
                BasisDiagnosisNodeResVO node = new BasisDiagnosisNodeResVO();
                node.setType(0);
                node.setRecordName(e.getQuestion());
                node.setRecordId(e.getId());
                node.setCorrect(requireCheckIdSet.contains(e.getAnswerId()) ? 1 : 0);
                return node;

            }).collect(Collectors.toList());
            basisDiagnosisNodeResVOS.addAll(qaList);
        }
        // 2.2 获取体格检查
        List<PhysicalRecordByResultDAO> physicalRecordList = diagnosisPhysicalRecordService.queryPhysicalResultByProcessId(processId);
        List<BasisDiagnosisNodeResVO> physicalList = physicalRecordList.stream()
                .filter(distinctPredicateNotNull(PhysicalRecordByResultDAO::getToolLocationName)).map(e -> {
            BasisDiagnosisNodeResVO nodeResVO = new BasisDiagnosisNodeResVO();
            nodeResVO.setType(1);
            nodeResVO.setRecordName(e.getToolLocationName());
            nodeResVO.setRecordId(e.getRecordId());
            // 如果是必做的,则是正确
            nodeResVO.setCorrect(null == e.getRequireCheck() ? Integer.valueOf(0) : e.getRequireCheck());
            return nodeResVO;
        }).collect(Collectors.toList());
        basisDiagnosisNodeResVOS.addAll(physicalList);
        // 2.3 获取辅助检查
        List<AncillaryRecordByResultDAO> ancillaryRecordList = diagnosisAncillaryRecordService.queryAncillaryResultByProcessId(processId);
        List<BasisDiagnosisNodeResVO> collect = ancillaryRecordList.stream()
                .filter(distinctPredicateNotNull(AncillaryRecordByResultDAO::getItemName)).map(e -> {
            BasisDiagnosisNodeResVO nodeResVO = new BasisDiagnosisNodeResVO();
            nodeResVO.setCorrect(null == e.getRequireCheck() ? Integer.valueOf(0) : e.getRequireCheck());
            nodeResVO.setRecordId(e.getRecordId());
            nodeResVO.setRecordName(e.getItemName());
            nodeResVO.setType(2);
            return nodeResVO;
        }).collect(Collectors.toList());
        basisDiagnosisNodeResVOS.addAll(collect);

        basisPrimaryResultResVO.setNodeList(basisDiagnosisNodeResVOS);
        return basisPrimaryResultResVO;
    }


    /**
     * 预期诊断结果
     */
    private ExpertDiagnosisResultResVO creatExpertDiagnosisResult(MedicalRec medicalRec, DiagnosisResult diagnosisResult, List<Disease> diseasesList) {
        ExpertDiagnosisResultResVO expertDiagnosisResultResVO = new ExpertDiagnosisResultResVO();
        expertDiagnosisResultResVO.setDiagnosis(StrUtil.join(";",diseasesList.stream().map(Disease::getDiseaseName).collect(Collectors.toList())));
        Set<String> expertDiseaseIdSet = diseasesList.stream().map(Disease::getId).collect(Collectors.toSet());
        List<Disease> userDiagnosisDiseaseList = CollUtil.isEmpty(diagnosisResult.getFinalDiagnosis()) ? CollUtil.newArrayList()
                : diseaseService.listByIds(diagnosisResult.getFinalDiagnosis());
        // 用户的诊断
        expertDiagnosisResultResVO.setUserDiagnosisResult(userDiagnosisDiseaseList.stream().map(e -> {
            DiagnosisDiseaseResultNodeVO userNode = new DiagnosisDiseaseResultNodeVO();
            userNode.setDiseaseName(e.getDiseaseName());
            // 如果用户诊断在预期诊断里面,则正确,否则错误
            userNode.setCorrect(expertDiseaseIdSet.contains(e.getId()) ? 1 : 0);
            userNode.setDiseaseId(e.getId());
            return userNode;
        }).collect(Collectors.toList()));

        // 预期诊断
        expertDiagnosisResultResVO.setExpertDiagnosisResult(diseasesList.stream().map(e -> {
            DiagnosisDiseaseResultNodeVO node = new DiagnosisDiseaseResultNodeVO();
            node.setDiseaseName(e.getDiseaseName());
            node.setDiseaseId(e.getId());
            return node;
        }).collect(Collectors.toList()));
        return expertDiagnosisResultResVO;
    }


    public static  <K> Predicate<K> distinctPredicateNotNull(Function<K,Object> function){
        ConcurrentHashMap<Object, Boolean> map = new ConcurrentHashMap<>();

        return t-> null != function.apply(t) && null == map.putIfAbsent(function.apply(t), true);

    }

}