package com.eitc.patient.service.impl;

import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
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.common.core.domain.entity.SysDept;
import com.eitc.common.utils.PatientBaseUtil;
import com.eitc.common.utils.bean.BeanUtils;
import com.eitc.patient.constant.PatientConstant;
import com.eitc.patient.domain.DiagnosisManage;
import com.eitc.patient.domain.DiagnosisType;
import com.eitc.patient.domain.DiagnosisTypeTemplate;
import com.eitc.patient.excel.DiagnosisTypeTemplateExcel;
import com.eitc.patient.mapper.DiagnosisTypeTemplateMapper;
import com.eitc.patient.service.IDiagnosisManageService;
import com.eitc.patient.service.IDiagnosisTypeService;
import com.eitc.patient.service.IDiagnosisTypeTemplateService;
import com.eitc.patient.vo.DiagnosisTypeTemplateSaveVO;
import com.eitc.system.service.ISysDeptService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * DiagnosisTypeTemplateServiceImpl
 *
 * @author mtx
 * @date: 2024/05/17 15:39
 */
@Service
public class DiagnosisTypeTemplateServiceImpl extends ServiceImpl<DiagnosisTypeTemplateMapper, DiagnosisTypeTemplate> implements IDiagnosisTypeTemplateService {

    @Resource
    private ISysDeptService sysDeptService;
    @Resource
    private IDiagnosisTypeService diagnosisTypeService;
    @Resource
    private IDiagnosisManageService diagnosisManageService;


    /**
     * 根据提供的模板示例字符串，查找并生成模板选项的JSON表示
     *
     * @param jsonContent 要获取json串的示例
     * @return json串
     * @author mtx
     * @date: 2024/5/20 14:50
     */
    @Override
    public String findTemplateInfo(String jsonContent) {
        JSONObject json = new JSONObject();
        JSONObject dicData = new JSONObject();
        List<String> keyList = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        // 拆分传过来的字符串，将字符串里的选项存到json里，并且根据第一个选项生成字符串
        if (StringUtils.isNotBlank(jsonContent)) {
            Matcher matcher = PatientConstant.COMPILE.matcher(jsonContent);
            while (matcher.find()) {
                String replacement = "_" + UUID.randomUUID().toString().replaceAll("-", "");
                keyList.add(replacement);
                // 获取内容
                String content = matcher.group(0);
                jsonContent = Pattern.compile(content, Pattern.LITERAL).matcher(jsonContent).replaceFirst(Matcher.quoteReplacement(replacement));

                // 获取选项
                String option = matcher.group(1);
                dicData.put(replacement, option.split("、"));
            }
        }
        // 将传过来的走传进行拆分
        JSONArray str = getJsonContent(jsonContent, dicData, sb, keyList);
        json.put("dic_data", dicData);
        json.put("text", sb.toString());
        json.put("str", str);
        return json.toJSONString();
    }

    /**
     * 将给定的字符串根据关键字列表拆分成JSON数组
     * 如果字符串为空，则返回包含空值的单个JSON对象的数组
     * 如果没有关键字，则直接返回包含原始字符串的单个JSON对象的数组
     * 否则，根据关键字将字符串拆分，并将拆分部分及其在字典数据中的对应选项（如果存在）转换为JSON对象，然后添加到数组中
     *
     * @param content 待处理的字符串
     * @param dicData 字典数据，包含关键字及其选项
     * @param sb 用于累加处理过程中的字符串
     * @param keyList 关键字列表，用于拆分字符串
     * @return 包含拆分字符串部分及其选项（如果存在）的JSON对象的数组
     */
    public JSONArray getJsonContent(String content, JSONObject dicData, StringBuilder sb, List<String> keyList) {
        JSONArray array = new JSONArray();
        JSONObject json;
        // 如果字符串为空，则直接返回空
        if (StringUtils.isBlank(content)){
            json = new JSONObject();
            json.put("type", "string");
            json.put("value", "");
            array.add(json);
            return array;
        }
        // 如果是字符串，没有选项，则直接返回字符串
        if (CollectionUtils.isEmpty(keyList)){
            sb.append(content);
            json = new JSONObject();
            json.put("type", "string");
            json.put("value", content);
            array.add(json);
            return array;
        }
        // 其他的拆分成json
        String jsonContent = content;
        for (int i = 0; i < keyList.size(); i++) {
            String key = keyList.get(i);
            String[] split = jsonContent.split(key);
            String str0 = split[0];
            if (StringUtils.isNotBlank(str0)) {
                sb.append(str0);
                json = new JSONObject();
                json.put("type", "string");
                json.put("value", str0);
                array.add(json);
            }

            JSONArray jsonArray = dicData.getJSONArray(key);
            if (Objects.nonNull(jsonArray)) {
                sb.append(jsonArray.get(0));
                json = new JSONObject();
                json.put("type", "select");
                json.put("val", jsonArray.get(0));
                json.put("value", key);
                array.add(json);
            }
            if(split.length<2){
                continue;
            }

            String str1 = split[1];
            if (StringUtils.isNotBlank(str1) && i == keyList.size() - 1) {
                sb.append(str1);
                json = new JSONObject();
                json.put("type", "string");
                json.put("value", str1);
                array.add(json);
            }
            jsonContent = str1;
        }
        return array;
    }

    /**
     * 导入诊断分类模板
     *
     * @param list            列表
     * @param diagnosisTypeId 诊断分类id
     * @return AjaxResult
     * @author mtx
     * @date: 2024/5/20 15:27
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public List<DiagnosisTypeTemplateExcel> importTemplate(List<DiagnosisTypeTemplateExcel> list, String diagnosisTypeId) {
        // 用于存储导入成功的诊断管理对象
        List<DiagnosisTypeTemplate> successList = new ArrayList<>();
        // 用于存储导入失败的诊断管理模板Excel对象，保留错误信息
        List<DiagnosisTypeTemplateExcel> errorList = new ArrayList<>();

        // 封装已存在的诊断管理
        List<DiagnosisManage> manageList = diagnosisManageService.list();
        Map<String, String> diagnosisCodeMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(manageList)) {
            diagnosisCodeMap = manageList.stream().collect(Collectors.toMap(DiagnosisManage::getId, DiagnosisManage::getDiagnosisName));
        }

        // 3.校验数据是否正确
        for (DiagnosisTypeTemplateExcel excel : list) {
            DiagnosisTypeTemplate template = new DiagnosisTypeTemplate();

            // 诊断分类
            try {
                checkClassify(excel, template);
            } catch (IllegalArgumentException e) {
                excel.setMsg(e.getMessage());
                errorList.add(excel);
                continue;
            }

            // 模板名称
            if (StringUtils.isEmpty(excel.getTemplateName())) {
                excel.setMsg("模板名称不能为空");
                errorList.add(excel);
                continue;
            }
            template.setTemplateName(excel.getTemplateName());

            // 诊断名称
            if (StringUtils.isEmpty(excel.getDiagnosisManageName())) {
                excel.setMsg("诊断名称不能为空");
                errorList.add(excel);
                continue;
            }
            if (!diagnosisCodeMap.containsValue(excel.getDiagnosisManageName())) {
                excel.setMsg("诊断名称不存在");
                errorList.add(excel);
                continue;
            }
            for (String id : diagnosisCodeMap.keySet()) {
                if (!diagnosisCodeMap.get(id).equals(excel.getDiagnosisManageName())) {
                    continue;
                }
                template.setDiagnosisManageId(id);
                template.setDiagnosisManageName(excel.getDiagnosisManageName());
            }

            // 模板描述
            if (StringUtils.isEmpty(excel.getTemplateDesc())) {
                excel.setMsg("模板描述不能为空");
                errorList.add(excel);
                continue;
            }
            template.setTemplateDesc(excel.getTemplateDesc());

            // 适用科室
            String applyDept = excel.getApplyDept();
            if (StringUtils.isEmpty(applyDept)) {
                excel.setMsg("适用科室不能为空");
                errorList.add(excel);
                continue;
            }
            List<Long> deptList = new ArrayList<>();
            try {
                String[] split = applyDept.split(",");
                for (String deptName : split) {
                    SysDept sd = new SysDept();
                    sd.setDeptName(deptName);
                    List<SysDept> sysDepts = sysDeptService.selectDeptList(sd);
                    if (CollectionUtils.isNotEmpty(sysDepts)) {
                        deptList.add(sysDepts.get(0).getDeptId());
                    } else {
                        throw new IllegalArgumentException("适用科室不存在");
                    }
                }
            } catch (IllegalArgumentException e) {
                excel.setMsg(e.getMessage());
                errorList.add(excel);
                continue;
            }
            template.setApplyDept(StringUtils.join(deptList, ","));

            // 就诊类型
            if (StringUtils.isEmpty(excel.getVisitType())) {
                excel.setMsg("就诊类型不能为空");
                errorList.add(excel);
                continue;
            }
            if ("初诊".equals(excel.getVisitType()) || "复诊".equals(excel.getVisitType())) {
                template.setVisitType("初诊".equals(excel.getVisitType()) ? 1 : 2);
            } else {
                excel.setMsg("就诊类型错误");
                errorList.add(excel);
                continue;
            }

            // 主诉
            if (StringUtils.isEmpty(excel.getChiefComplaintContent())) {
                excel.setMsg("主诉不能为空");
                errorList.add(excel);
                continue;
            }
            template.setChiefComplaintContent(excel.getChiefComplaintContent());

            // 现病史
            if (template.getVisitType() == 1 && StringUtils.isBlank(excel.getPresentIllnessContent())) {
                throw new IllegalArgumentException("初诊必须填写现病史");
            }
            template.setPresentIllnessContent(excel.getPresentIllnessContent());

            // 检查
            if (StringUtils.isEmpty(excel.getInspectContent())) {
                excel.setMsg("检查不能为空");
                errorList.add(excel);
                continue;
            }
            template.setInspectContent(excel.getInspectContent());

            // 治疗计划
            if (StringUtils.isEmpty(excel.getTreatmentPlanningContent())) {
                excel.setMsg("治疗计划不能为空");
                errorList.add(excel);
                continue;
            }
            template.setTreatmentPlanningContent(excel.getTreatmentPlanningContent());

            // 处置
            if (StringUtils.isEmpty(excel.getDisposeContent())) {
                excel.setMsg("处置不能为空");
                errorList.add(excel);
                continue;
            }
            template.setDisposeContent(excel.getDisposeContent());

            // 便签
            if (StringUtils.isNotBlank(excel.getNoteContent())) {
                template.setNoteContent(excel.getNoteContent());
            }

            // 设置主诉选项
            saveDiagnosisOption(template);
            // 默认未启用
            template.setEnableStatus(0);

            successList.add(template);
        }
        // 保存数据并返回
        if (CollectionUtils.isNotEmpty(successList)) {
            this.saveBatch(successList);
        }
        // 返回导入失败的列表，外部可用于显示错误信息
        return errorList;
    }

    private void checkClassify(DiagnosisTypeTemplateExcel excel, DiagnosisTypeTemplate template) {
        if (StringUtils.isNotBlank(excel.getClassifyOne())) {
            List<DiagnosisType> list1 = diagnosisTypeService.list(Wrappers.<DiagnosisType>lambdaQuery()
                    .eq(DiagnosisType::getParentId, "0")
                    .eq(DiagnosisType::getDiagnosisName, excel.getClassifyOne()));
            if (CollectionUtils.isNotEmpty(list1)) {
                if (StringUtils.isNotBlank(excel.getClassifyTwo())) {
                    List<DiagnosisType> list2 = diagnosisTypeService.list(Wrappers.<DiagnosisType>lambdaQuery()
                            .eq(DiagnosisType::getParentId, list1.get(0).getId())
                            .eq(DiagnosisType::getDiagnosisName, excel.getClassifyTwo()));
                    if (CollectionUtils.isNotEmpty(list2)) {
                        if (StringUtils.isNotBlank(excel.getClassifyThree())) {
                            List<DiagnosisType> list3 = diagnosisTypeService.list(Wrappers.<DiagnosisType>lambdaQuery()
                                    .eq(DiagnosisType::getParentId, list2.get(0).getId())
                                    .eq(DiagnosisType::getDiagnosisName, excel.getClassifyThree()));
                            if (CollectionUtils.isNotEmpty(list3)) {
                                if (StringUtils.isNotBlank(excel.getClassifyFour())) {
                                    List<DiagnosisType> list4 = diagnosisTypeService.list(Wrappers.<DiagnosisType>lambdaQuery()
                                            .eq(DiagnosisType::getParentId, list3.get(0).getId())
                                            .eq(DiagnosisType::getDiagnosisName, excel.getClassifyFour()));
                                    if (CollectionUtils.isNotEmpty(list4)) {
                                        if (StringUtils.isNotBlank(excel.getClassifyFive())) {
                                            List<DiagnosisType> list5 = diagnosisTypeService.list(Wrappers.<DiagnosisType>lambdaQuery()
                                                    .eq(DiagnosisType::getParentId, list4.get(0).getId())
                                                    .eq(DiagnosisType::getDiagnosisName, excel.getClassifyFive()));
                                            if (CollectionUtils.isNotEmpty(list5)) {
                                                if (StringUtils.isNotBlank(excel.getClassifySix())) {
                                                    List<DiagnosisType> list6 = diagnosisTypeService.list(Wrappers.<DiagnosisType>lambdaQuery()
                                                            .eq(DiagnosisType::getParentId, list5.get(0).getId())
                                                            .eq(DiagnosisType::getDiagnosisName, excel.getClassifySix()));
                                                    if (CollectionUtils.isNotEmpty(list6)) {
                                                        // 校验是否可以添加模板
                                                        diagnosisTypeService.checkAddDiagnosisType(list6.get(0).getId());
                                                        template.setDiagnosisTypeId(list6.get(0).getId());
                                                    } else {
                                                        throw new IllegalArgumentException("六级分类不存在");
                                                    }
                                                } else {
                                                    // 校验是否可以添加模板
                                                    diagnosisTypeService.checkAddDiagnosisType(list5.get(0).getId());
                                                    template.setDiagnosisTypeId(list5.get(0).getId());
                                                }
                                            } else {
                                                throw new IllegalArgumentException("五级分类不存在");
                                            }
                                        } else {
                                            // 校验是否可以添加模板
                                            diagnosisTypeService.checkAddDiagnosisType(list4.get(0).getId());
                                            template.setDiagnosisTypeId(list4.get(0).getId());
                                        }
                                    } else {
                                        throw new IllegalArgumentException("四级分类不存在");
                                    }
                                } else {
                                    // 校验是否可以添加模板
                                    diagnosisTypeService.checkAddDiagnosisType(list3.get(0).getId());
                                    template.setDiagnosisTypeId(list3.get(0).getId());
                                }
                            } else {
                                throw new IllegalArgumentException("三级分类不存在");
                            }
                        } else {
                            // 校验是否可以添加模板
                            diagnosisTypeService.checkAddDiagnosisType(list2.get(0).getId());
                            template.setDiagnosisTypeId(list2.get(0).getId());
                        }
                    } else {
                        throw new IllegalArgumentException("二级分类不存在");
                    }
                } else {
                    // 校验是否可以添加模板
                    diagnosisTypeService.checkAddDiagnosisType(list1.get(0).getId());
                    template.setDiagnosisTypeId(list1.get(0).getId());
                }
            } else {
                throw new IllegalArgumentException("一级分类不存在");
            }
        } else {
            throw new IllegalArgumentException("一级分类不能为空");
        }
    }

    /**
     * 新增或修改诊断模板
     *
     * @param entry 参数
     * @author mtx
     * @date: 2024/6/7 14:06
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void add(DiagnosisTypeTemplateSaveVO entry) {
        // 校验是否可以添加模板
        diagnosisTypeService.checkAddDiagnosisType(entry.getDiagnosisTypeId());
        this.save(getDiagnosisTypeTemplate(entry));
    }

    /**
     * 修改诊断模板
     *
     * @param entry 参数
     * @author mtx
     * @date: 2024/6/7 14:06
     */
    @Override
    public void edit(DiagnosisTypeTemplateSaveVO entry) {
        if (StringUtils.isEmpty(entry.getId())) {
            throw new IllegalArgumentException("id不能为空");
        }
        this.updateById(getDiagnosisTypeTemplate(entry));
    }

    /**
     * 根据提供的诊断类型模板保存视图对象，构建并返回一个新的 DiagnosisTypeTemplate 实例
     * 该方法主要用于处理诊断类型模板的保存逻辑，其中包括复制视图对象属性、验证诊断管理ID、
     * 设置诊断管理名称以及处理适用部门列表
     *
     * @param entry 诊断类型模板保存视图对象，用于接收前端传入的诊断类型模板信息
     * @return 返回构建好的 DiagnosisTypeTemplate 实例
     */
    private DiagnosisTypeTemplate getDiagnosisTypeTemplate(DiagnosisTypeTemplateSaveVO entry) {
        if (entry.getVisitType() == 1 && StringUtils.isBlank(entry.getPresentIllnessContent())) {
            throw new IllegalArgumentException("初诊必须填写现病史");
        }

        // 初始化 DiagnosisTypeTemplate 实例
        DiagnosisTypeTemplate diagnosisTypeTemplate = new DiagnosisTypeTemplate();
        // 将视图对象的属性复制到 DiagnosisTypeTemplate 实例中
        BeanUtils.copyProperties(entry, diagnosisTypeTemplate);
        // 根据提供的ID获取诊断管理实体
        DiagnosisManage manage = diagnosisManageService.getById(entry.getDiagnosisManageId());
        // 若诊断管理ID不存在，则抛出参数异常
        if (Objects.isNull(manage)) {
            throw new IllegalArgumentException("诊断管理id不存在");
        }
        // 设置 DiagnosisTypeTemplate 的诊断管理名称
        diagnosisTypeTemplate.setDiagnosisManageName(manage.getDiagnosisName());
        // 获取适用部门列表
        List<Long> applyDeptList = entry.getApplyDeptList();
        // 若适用部门列表不为空，则将其转换为以逗号分隔的字符串，并设置到 DiagnosisTypeTemplate 中
        if (CollectionUtils.isEmpty(applyDeptList)) {
            throw new IllegalArgumentException("适用科室不能为空");
        }
        diagnosisTypeTemplate.setApplyDept(StringUtils.join(applyDeptList, ","));
        // 设置主诉选项
        saveDiagnosisOption(diagnosisTypeTemplate);

        // 返回构建好的 DiagnosisTypeTemplate 实例
        return diagnosisTypeTemplate;
    }

    /**
     * 保存诊断选项
     * 此方法用于将诊断类型模板中的诊断内容设置到相应的选项中
     * 它通过将各个诊断部分的内容赋值给模板的相应选项，来简化诊断信息的管理和使用
     *
     * @param diagnosisTypeTemplate 诊断类型模板，包含各种诊断内容和对应的选项
     */
    private void saveDiagnosisOption(DiagnosisTypeTemplate diagnosisTypeTemplate) {
        // 首拼
        diagnosisTypeTemplate.setNamePinyinFirstLetter(PatientBaseUtil.getPinYinFirstLetter(diagnosisTypeTemplate.getTemplateName()));
        diagnosisTypeTemplate.setNamePinyin(PatientBaseUtil.getPinyin(diagnosisTypeTemplate.getTemplateName()));

        diagnosisTypeTemplate.setChiefComplaintOption(this.findTemplateInfo(diagnosisTypeTemplate.getChiefComplaintContent()));
        diagnosisTypeTemplate.setPresentIllnessOption(this.findTemplateInfo(diagnosisTypeTemplate.getPresentIllnessContent()));
        diagnosisTypeTemplate.setInspectOption(this.findTemplateInfo(diagnosisTypeTemplate.getInspectContent()));
        diagnosisTypeTemplate.setTreatmentPlanningOption(this.findTemplateInfo(diagnosisTypeTemplate.getTreatmentPlanningContent()));
        diagnosisTypeTemplate.setDisposeOption(this.findTemplateInfo(diagnosisTypeTemplate.getDisposeContent()));
        diagnosisTypeTemplate.setNoteOption(this.findTemplateInfo(diagnosisTypeTemplate.getNoteContent()));
    }

}
