package com.eitc.patient.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.eitc.patient.constant.PatientConstant;
import com.eitc.patient.domain.DiagnosisType;
import com.eitc.patient.domain.DiagnosisTypeTemplate;
import com.eitc.patient.domain.MedicalHistory;
import com.eitc.patient.domain.MedicalRecord;
import com.eitc.patient.domain.MedicalRecordDetails;
import com.eitc.patient.domain.PatientAppointment;
import com.eitc.patient.dto.MedicalRecordListDto;
import com.eitc.patient.enums.MedicalHistoryDiseaseSourceEnum;
import com.eitc.patient.enums.MedicalHistoryDiseaseTypeEnum;
import com.eitc.patient.enums.MedicalRecordStatusEnum;
import com.eitc.patient.enums.PatientAppointmentStatusEnum;
import com.eitc.patient.mapper.MedicalRecordMapper;
import com.eitc.patient.service.ICollectCostPatientsService;
import com.eitc.patient.service.IDiagnosisTypeService;
import com.eitc.patient.service.IDiagnosisTypeTemplateService;
import com.eitc.patient.service.IMedicalHistoryService;
import com.eitc.patient.service.IMedicalRecordDetailsService;
import com.eitc.patient.service.IMedicalRecordService;
import com.eitc.patient.service.IPatientAppointmentService;
import com.eitc.patient.vo.FormattedPartsVO;
import com.eitc.patient.vo.MedicalRecordDetailsVO;
import com.eitc.patient.vo.MedicalRecordParamVO;
import com.eitc.patient.vo.MedicalRecordVO;
import com.eitc.system.utils.UserCacheUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * MedicalRecordServiceImpl
 *
 * @author mtx
 * @date: 2024/05/17 15:39
 */
@Service
public class MedicalRecordServiceImpl extends ServiceImpl<MedicalRecordMapper, MedicalRecord> implements IMedicalRecordService {

    @Resource
    private IMedicalHistoryService medicalHistoryService;
    @Resource
    private IMedicalRecordDetailsService medicalRecordDetailsService;
    @Resource
    private IDiagnosisTypeTemplateService diagnosisTypeTemplateService;
    @Resource
    private IDiagnosisTypeService diagnosisTypeService;
    @Resource
    private IPatientAppointmentService patientAppointmentService;
    @Resource
    private ICollectCostPatientsService collectCostPatientsService;

    /**
     * 保存或编辑病历信息。
     *
     * @param vo 包含病历及相关信息的参数对象。
     * @author mtx
     * @date 2024/5/22 10:00
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void addOrEdit(MedicalRecordParamVO vo) {
        // 检查病历详情列表是否为空
        List<MedicalRecordVO> dataList = vo.getDataList();
        if (CollectionUtils.isEmpty(dataList)) {
            throw new RuntimeException("病历详情不能为空");
        }

        // 初始化病历对象并设置基本信息，保存病历信息
        MedicalRecord medicalRecord = saveMedicalRecordInfo(vo);

        // 保存个人录入的病史信息到病历记录中
        medicalHistoryService.saveMedicalHistoryToMedicalRecordIdByPatientId(medicalRecord.getPatientId(), medicalRecord.getId());

        // 初始化标志位和计数器，用于后续处理
        AtomicBoolean flag = new AtomicBoolean(true);
        AtomicInteger num = new AtomicInteger(1);
        List<MedicalRecordDetails> recordDetailsList = new ArrayList<>();

        // 遍历病历详情列表，处理每条详情信息
        dataList.forEach(medicalRecordVO -> {
            List<MedicalRecordDetailsVO> data = medicalRecordVO.getData();

            data.forEach(medicalRecordDetailsVO -> {
                MedicalRecordDetails recordDetails = saveMedicalRecordDetails(medicalRecord.getId(), flag, num,
                        medicalRecordVO.getToothStatus(), medicalRecordVO.getToothPosition(), medicalRecordDetailsVO);
                recordDetailsList.add(recordDetails);
            });
        });

        // 修改预约状态
        if (StringUtils.isNotBlank(vo.getAppointmentId())) {
            PatientAppointment appointment = new PatientAppointment();
            appointment.setId(vo.getAppointmentId());
            appointment.setMedicalRecordId(medicalRecord.getId());
            appointment.setAppointmentStatus(flag.get() ? PatientAppointmentStatusEnum.TREATMENT_COMPLETED.getCode() : PatientAppointmentStatusEnum.IN_TREATMENT.getCode());
            patientAppointmentService.updateById(appointment);
        }

        // 删除旧的病历详情信息，然后保存新的病历详情信息
        medicalRecordDetailsService.remove(Wrappers.<MedicalRecordDetails>lambdaQuery().eq(MedicalRecordDetails::getMedicalRecordId, medicalRecord.getId()));
        medicalRecordDetailsService.saveBatch(recordDetailsList);

        // 保存收费信息
        BigDecimal bigDecimal = collectCostPatientsService.saveCollectCostPatientsToMedicalRecord(recordDetailsList, medicalRecord.getPatientId());
        // 根据病历ID更新病历状态
        MedicalRecord mr = new MedicalRecord();
        mr.setStatus(flag.get() ? MedicalRecordStatusEnum.ALREADY_COMPLETE.getCode() : MedicalRecordStatusEnum.WAIT_COMPLETE.getCode());
        mr.setId(medicalRecord.getId());
        mr.setCost(bigDecimal);
        this.updateById(mr);
    }

    /**
     * 封装病历详情信息。
     *
     * @param medicalRecordId        病历
     * @param flag                   标志位
     * @param num                    排序
     * @param toothStatus            牙位状态
     * @param toothPosition          牙位
     * @param medicalRecordDetailsVO 病历详情VO
     * @return 返回结果
     * @author mtx
     * @date: 2024/7/18 15:01
     */
    private MedicalRecordDetails saveMedicalRecordDetails(String medicalRecordId, AtomicBoolean flag, AtomicInteger num, Integer toothStatus, String toothPosition, MedicalRecordDetailsVO medicalRecordDetailsVO) {
        // 根据诊断类型模板ID获取模板信息
        String templateId = medicalRecordDetailsVO.getDiagnosisTypeTemplateId();
        DiagnosisTypeTemplate diagnosisTypeTemplate = diagnosisTypeTemplateService.getById(templateId);
        if (Objects.isNull(diagnosisTypeTemplate)) {
            throw new RuntimeException("诊断分类模板表获取失败");
        }

        // 处理选择项信息，如选项拼接
        String option = "";
        if (Objects.nonNull(medicalRecordDetailsVO.getFormattedParts())) {
            option = medicalRecordDetailsVO.getFormattedParts().stream()
                    .filter(li -> "select".equals(li.getType()))
                    .map(FormattedPartsVO::getValue)
                    .collect(Collectors.joining(","));
        }

        // 初始化并设置病历详情对象属性
        MedicalRecordDetails recordDetails = new MedicalRecordDetails();
        recordDetails.setMedicalRecordId(medicalRecordId);
        recordDetails.setDiagnosisTypeTemplateId(templateId);
        recordDetails.setDiagnosisTypeId(diagnosisTypeTemplate.getDiagnosisTypeId());
        DiagnosisType diagnosisType = diagnosisTypeService.getById(diagnosisTypeTemplate.getDiagnosisTypeId());
        if (Objects.nonNull(diagnosisType)) {
            recordDetails.setDiagnosisTypeName(diagnosisType.getDiagnosisName());
        }
        recordDetails.setToothPosition(toothPosition);
        if (Objects.isNull(toothStatus) || !MedicalRecordStatusEnum.ALREADY_COMPLETE.getCode().equals(toothStatus)) {
            flag.set(false);
        }
        recordDetails.setToothStatus(toothStatus);
        recordDetails.setTemplateName(medicalRecordDetailsVO.getTemplateName());
        recordDetails.setTemplateExample(medicalRecordDetailsVO.getTemplateExample());
        recordDetails.setTemplateInfo(medicalRecordDetailsVO.getTemplateInfo());
        recordDetails.setTemplateOption(option);
        recordDetails.setOrderNum(num.getAndIncrement());

        String templateExample = recordDetails.getTemplateExample();
        String templateInfo = diagnosisTypeTemplateService.findTemplateInfo(templateExample);

        recordDetails.setContentInfo(
                encapsulationTemplateInfo(templateInfo, recordDetails.getTemplateOption()));

        List<String> list = new ArrayList<>();
        String patientMedicalRecord = medicalRecordDetailsVO.getPatientMedicalRecord();
        if (StringUtils.isNotBlank(patientMedicalRecord)) {
            list.addAll(Arrays.asList(patientMedicalRecord.split(",")));
        }
        if ("过敏史".equals(medicalRecordDetailsVO.getTemplateName())) {
            String collect = medicalRecordDetailsVO.getFormattedPartsList().stream()
                    .filter(li -> !list.contains(li)).collect(Collectors.joining(","));

            // 保存医生填写的病史
            medicalHistoryService.saveMedicalHistoryList(
                    collect, null, null,
                    medicalRecordId, null, MedicalHistoryDiseaseSourceEnum.DOCTOR.getCode());
        }
        if ("既往史".equals(medicalRecordDetailsVO.getTemplateName())) {
            String collect = medicalRecordDetailsVO.getFormattedPartsList().stream()
                    .filter(li -> !list.contains(li)).collect(Collectors.joining(","));
            // 保存医生填写的病史
            medicalHistoryService.saveMedicalHistoryList(
                    null, collect, null,
                    medicalRecordId, null, MedicalHistoryDiseaseSourceEnum.DOCTOR.getCode());
        }
        if ("家族史".equals(medicalRecordDetailsVO.getTemplateName())) {
            String collect = medicalRecordDetailsVO.getFormattedPartsList().stream()
                    .filter(li -> !list.contains(li)).collect(Collectors.joining(","));
            // 保存医生填写的病史
            medicalHistoryService.saveMedicalHistoryList(
                    null, null, collect,
                    medicalRecordId, null, MedicalHistoryDiseaseSourceEnum.DOCTOR.getCode());
        }

        String jsonString = JSONArray.toJSONString(medicalRecordDetailsVO.getFormattedParts());
        recordDetails.setTemplateView(jsonString);
        return recordDetails;
    }

    /**
     * 初始化病历对象并设置基本信息，保存病历信息
     *
     * @param vo 参数
     * @return 返回
     */
    @Transactional(rollbackFor = {Exception.class})
    public MedicalRecord saveMedicalRecordInfo(MedicalRecordParamVO vo) {
        MedicalRecord medicalRecord = new MedicalRecord();
        medicalRecord.setAttendingDoctorId(vo.getAttendingDoctorId());
        medicalRecord.setAttendingDoctorName(UserCacheUtil.getSysUserById(vo.getAttendingDoctorId()).getNickName());
        medicalRecord.setPatientId(vo.getPatientId());
        medicalRecord.setStatus(vo.getStatus());
        medicalRecord.setOutpatientService(UserCacheUtil.getClinicName());
        medicalRecord.setDepartment(UserCacheUtil.getSysDeptByUserId(vo.getAttendingDoctorId()).getDeptName());
        medicalRecord.setCost(BigDecimal.ZERO);

        if (Objects.nonNull(vo.getId())) {
            medicalRecord.setId(vo.getId());
        } else {
            long count = this.count(Wrappers.<MedicalRecord>lambdaQuery().eq(MedicalRecord::getPatientId, medicalRecord.getPatientId()));
            medicalRecord.setVisitType(count > 0 ? 2 : 1);
        }
        this.saveOrUpdate(medicalRecord);
        return medicalRecord;
    }

    /**
     * 封装病历信息
     *
     * @param medicalRecord 病历信息
     * @return 病历信息
     * @author mtx
     * @date: 2024/5/23 9:17
     */
    @Override
    public MedicalRecordParamVO getMedicalRecordVO(MedicalRecord medicalRecord) {
        // 创建一个新的VO对象，用于存储处理后的病历信息
        MedicalRecordParamVO vo = new MedicalRecordParamVO();
        // 将病历实体的基本信息赋值给VO对象
        vo.setId(medicalRecord.getId());
        vo.setVisitType(medicalRecord.getVisitType());
        vo.setStatus(medicalRecord.getStatus());
        vo.setPatientId(medicalRecord.getPatientId());
        vo.setAttendingDoctorId(medicalRecord.getAttendingDoctorId());
        vo.setAttendingDoctorName(medicalRecord.getAttendingDoctorName());

        vo.setDepartment(medicalRecord.getDepartment());
        vo.setCost(BigDecimal.ZERO);
        vo.setClinicName(medicalRecord.getOutpatientService());
        vo.setCreateDate(medicalRecord.getCreateDate());

        // 初始化存储详细数据的列表
        List<MedicalRecordVO> dataList = new ArrayList<>();
        // 根据病历ID查询详细的医疗记录
        List<MedicalRecordDetails> list = medicalRecordDetailsService.list(Wrappers.<MedicalRecordDetails>lambdaQuery()
                .eq(MedicalRecordDetails::getMedicalRecordId, medicalRecord.getId())
                .orderByAsc(MedicalRecordDetails::getOrderNum));
        // 将详细信息按牙齿位置分组
        Map<String, List<MedicalRecordDetails>> collect = list.stream().collect(Collectors.groupingBy(MedicalRecordDetails::getToothPosition));
        // 遍历分组后的数据
        for (String key : collect.keySet()) {
            MedicalRecordVO medicalRecordVO = new MedicalRecordVO();
            medicalRecordVO.setToothPosition(key);

            List<MedicalRecordDetails> detailsList = collect.get(key);
            // 如果详细数据为空，则在VO中设置为空列表
            if (CollectionUtils.isEmpty(detailsList)) {
                medicalRecordVO.setData(new ArrayList<>());
            } else {
                // 处理每个牙齿的详细信息，并将其添加到VO中
                List<MedicalRecordDetailsVO> details = new ArrayList<>();
                detailsList.stream().sorted(Comparator.comparing(MedicalRecordDetails::getOrderNum)).forEach(li -> {
                    MedicalRecordDetailsVO medicalRecordDetailsVO = new MedicalRecordDetailsVO();

                    // 根据模板名称，填充VO中的对应信息
                    if ("诊断".equals(li.getTemplateName()) && StringUtils.isBlank(vo.getDiagnosisTypeCn())) {
                        vo.setDiagnosisTypeCn(li.getDiagnosisTypeName());
                    }
                    if ("治疗计划".equals(li.getTemplateName()) && StringUtils.isBlank(vo.getTreatment())) {
                        vo.setTreatment(li.getContentInfo());
                    }
                    medicalRecordVO.setToothStatus(li.getToothStatus());

                    // 将详细信息的各个字段从实体对象复制到VO对象
                    medicalRecordDetailsVO.setMedicalRecordDetailsId(li.getId());
                    medicalRecordDetailsVO.setDiagnosisTypeTemplateId(li.getDiagnosisTypeTemplateId());
                    medicalRecordDetailsVO.setDiagnosisTypeId(li.getDiagnosisTypeId());
                    medicalRecordDetailsVO.setDiagnosisTypeCn(li.getDiagnosisTypeName());
                    medicalRecordDetailsVO.setTemplateName(li.getTemplateName());
                    medicalRecordDetailsVO.setTemplateExample(li.getTemplateExample());
                    medicalRecordDetailsVO.setTemplateExample2(li.getTemplateExample());
                    medicalRecordDetailsVO.setContentInfo(li.getContentInfo());
                    medicalRecordDetailsVO.setTemplateInfo(li.getTemplateInfo());
                    medicalRecordDetailsVO.setTemplateOption(li.getTemplateOption());

                    // 根据病历ID查询相关的病史信息，并根据类型进行处理
                    List<MedicalHistory> histories = medicalHistoryService.list(Wrappers.<MedicalHistory>lambdaQuery().eq(MedicalHistory::getMedicalRecordId, li.getMedicalRecordId()));
                    if (MedicalHistoryDiseaseTypeEnum.ALLERGY_HISTORY.getInfo().equals(li.getTemplateName())) {
                        findMedicalHistory(medicalRecordDetailsVO, histories, MedicalHistoryDiseaseTypeEnum.ALLERGY_HISTORY.getCode());
                    } else if (MedicalHistoryDiseaseTypeEnum.PAST_HISTORY.getInfo().equals(li.getTemplateName())) {
                        findMedicalHistory(medicalRecordDetailsVO, histories, MedicalHistoryDiseaseTypeEnum.PAST_HISTORY.getCode());
                    } else if (MedicalHistoryDiseaseTypeEnum.FAMILY_HISTORY.getInfo().equals(li.getTemplateName())) {
                        findMedicalHistory(medicalRecordDetailsVO, histories, MedicalHistoryDiseaseTypeEnum.FAMILY_HISTORY.getCode());
                    }

                    // 处理模板视图信息，并将其转换为VO对象
                    medicalRecordDetailsVO.setFormattedParts(JSONArray.parseArray(li.getTemplateView(), FormattedPartsVO.class));
                    details.add(medicalRecordDetailsVO);
                });
                // 将处理后的详细数据添加到VO中
                medicalRecordVO.setData(details);
            }
            dataList.add(medicalRecordVO);
        }

        vo.setDataList(dataList);
        return vo;
    }

    /**
     * 病历列表
     *
     * @param searchParam 病历信息
     * @return 病历列表
     * @author mtx
     * @date: 2024/5/23 9:17
     */
    @Override
    public List<MedicalRecordListDto> medicalRecordList(String searchParam) {
        List<MedicalRecordListDto> dtos = this.getBaseMapper().medicalRecordList(null);
        if (CollectionUtils.isEmpty(dtos)) {
            return dtos;
        }
        for (MedicalRecordListDto dto : dtos) {
            String id = dto.getId();
            List<MedicalRecordDetails> list = medicalRecordDetailsService.list(Wrappers.<MedicalRecordDetails>lambdaQuery()
                    .eq(MedicalRecordDetails::getMedicalRecordId, id));
            if(CollectionUtils.isEmpty(list)){
                continue;
            }
            String collect = list.stream().map(MedicalRecordDetails::getContentInfo)
                    .filter(StringUtils::isNotBlank).collect(Collectors.joining(","));
            dto.setContentInfo(collect);
        }
        if(StringUtils.isNotBlank(searchParam)){
            dtos = dtos.stream().filter(dto -> dto.getContentInfo().contains(searchParam)
                    || dto.getAttendingDoctorName().contains(searchParam)
                    || dto.getPatientName().contains(searchParam)).collect(Collectors.toList());
        }
        return dtos;
    }

    /**
     * 根据用户编号和疾病类型，查找并设置病人的医疗记录详情。
     * 此方法会分别筛选出患者自述和医生诊断的疾病内容，并将其分别设置到医疗记录详情对象中。
     * 同时，还会设置一份格式化的疾病内容列表。
     *
     * @param medicalRecordDetailsVO 医疗记录详情对象，用于存储查询结果。
     * @param histories              病历库中的所有病历记录列表。
     * @param diseaseType            疾病类型，用于筛选特定类型的病历。
     */
    private void findMedicalHistory(MedicalRecordDetailsVO medicalRecordDetailsVO, List<MedicalHistory> histories, Integer diseaseType) {
        // 根据疾病类型筛选出相应的病历记录
        List<MedicalHistory> collect = histories.stream().filter(l -> diseaseType.equals(l.getDiseaseType())).collect(Collectors.toList());

        // 设置患者自述的疾病内容，以逗号分隔
        medicalRecordDetailsVO.setPatientMedicalRecord(collect.stream()
                .filter(l -> MedicalHistoryDiseaseSourceEnum.PATIENT.getCode().equals(l.getDiseaseSource()))
                .map(MedicalHistory::getDiseaseContent).collect(Collectors.joining(",")));

        // 设置医生诊断的疾病内容，以逗号分隔
        medicalRecordDetailsVO.setDoctorMedicalRecord(collect.stream()
                .filter(l -> MedicalHistoryDiseaseSourceEnum.DOCTOR.getCode().equals(l.getDiseaseSource()))
                .map(MedicalHistory::getDiseaseContent).collect(Collectors.joining(",")));

        // 设置格式化的疾病内容列表，包含所有病历的疾病内容
        medicalRecordDetailsVO.setFormattedPartsList(collect.stream().map(MedicalHistory::getDiseaseContent).collect(Collectors.toList()));
    }

    /**
     * 根据模板选项，将模板选项替换成模板示例
     *
     * @param templateInfo   模板信息
     * @param templateOption 模板选项
     * @return 替换后的数据
     * @author mtx
     * @date: 2024/5/23 9:15
     */
    public String encapsulationTemplateInfo(String templateInfo, String templateOption) {
        if (StringUtils.isEmpty(templateInfo)) {
            return null;
        }

        String[] split = templateOption.split(",");
        String keyPrefix = PatientConstant.DIAGNOSIS_TYPE_TEMPLATE_KEY_PREFIX;
        int count = 0, i = 0;
        while (templateInfo.indexOf(keyPrefix, i) >= 0) {
            count++;
            i = templateInfo.indexOf(keyPrefix, i) + keyPrefix.length();
        }

        for (int j = 0; j < count; j++) {
            int i1 = j + 1;
            String s = "";
            try {
                s = split[j];
            } catch (Exception ignored) {
            }
            templateInfo = templateInfo.replace(keyPrefix + i1, s);
        }
        return templateInfo;
    }
}
