package com.xinelu.manage.service.labelfieldcontent.impl;

import com.alibaba.fastjson2.JSONObject;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.enums.PatientSexEnum;
import com.xinelu.common.enums.PortraitStatusEnum;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.common.utils.BaseUtil;
import com.xinelu.common.utils.SecurityUtils;
import com.xinelu.common.utils.bean.BeanUtils;
import com.xinelu.manage.domain.labelfieldcontent.LabelFieldContent;
import com.xinelu.manage.domain.labelfieldinfo.LabelFieldInfo;
import com.xinelu.manage.domain.patientinfo.PatientAllInfoView;
import com.xinelu.manage.domain.patientinfo.PatientAllInfoViewUppercase;
import com.xinelu.manage.domain.signpatientmanageroutenode.SignPatientManageRouteNode;
import com.xinelu.manage.dto.labelfieldcontent.LabelFieldContentAddDTO;
import com.xinelu.manage.dto.labelfieldcontent.LabelFieldContentDTO;
import com.xinelu.manage.dto.signpatientmanageroutenode.PatientTaskDto;
import com.xinelu.manage.mapper.labelfieldcontent.LabelFieldContentMapper;
import com.xinelu.manage.mapper.labelfieldinfo.LabelFieldInfoMapper;
import com.xinelu.manage.mapper.patientinfo.PatientAllInfoViewMapper;
import com.xinelu.manage.mapper.signpatientmanageroutenode.SignPatientManageRouteNodeMapper;
import com.xinelu.manage.service.labelfieldcontent.ILabelFieldContentService;
import com.xinelu.manage.vo.labelfieldcontent.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 标签字段内容信息Service业务层处理
 *
 * @author xinelu
 * @date 2024-03-11
 */
@Service
public class LabelFieldContentServiceImpl implements ILabelFieldContentService {
    @Resource
    private LabelFieldContentMapper labelFieldContentMapper;
    @Resource
    private LabelFieldInfoMapper labelFieldInfoMapper;
    @Resource
    private PatientAllInfoViewMapper patientAllInfoViewMapper;
    @Resource
    private SignPatientManageRouteNodeMapper signPatientManageRouteNodeMapper;

    /**
     * 查询标签字段内容信息
     *
     * @param id 标签字段内容信息主键
     * @return 标签字段内容信息
     */
    @Override
    public LabelFieldContent selectLabelFieldContentById(Long id) {
        return labelFieldContentMapper.selectLabelFieldContentById(id);
    }

    /**
     *
     * @param patientId
     * @return
     */
    @Override
    public List<LabelFieldContent>  selectLabelFieldContentByPatientId(Long patientId){
        return labelFieldContentMapper.selectLabelFieldContentByPatientId(patientId);
    }

    /**
     * 批量查询标签字段内容信息对象
     *
     * @param patientId 患者信息
     * @return LabelFieldContent
     */
    @Override
    public List<LabelFieldContent> selectLabelFieldContentByPatientIds(List<Long> patientId) {
        return labelFieldContentMapper.selectLabelFieldContentByPatientIds(patientId);
    }

    /**
     * 查询标签字段内容信息列表
     *
     * @param labelFieldContent 标签字段内容信息
     * @return 标签字段内容信息
     */
    @Override
    public List<LabelFieldContent> selectLabelFieldContentList(LabelFieldContent labelFieldContent) {
        return labelFieldContentMapper.selectLabelFieldContentList(labelFieldContent);
    }

    /**
     * 新增标签字段内容信息
     *
     * @param labelFieldContent 标签字段内容信息
     * @return 结果
     */
    @Override
    public int insertLabelFieldContent(LabelFieldContent labelFieldContent) {
        labelFieldContent.setPortraitSn(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        labelFieldContent.setCreateTime(LocalDateTime.now());
        return labelFieldContentMapper.insertLabelFieldContent(labelFieldContent);
    }

    /**
     * 修改标签字段内容信息
     *
     * @param labelFieldContent 标签字段内容信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateLabelFieldContent(LabelFieldContent labelFieldContent) {
        if (ObjectUtils.isEmpty(labelFieldContentMapper.selectLabelFieldContentById(labelFieldContent.getId()))) {
            throw new ServiceException("当前字段内容不存在，无法修改，请联系管理员");
        }
        labelFieldContent.setUpdateBy(SecurityUtils.getUsername());
        labelFieldContent.setUpdateTime(LocalDateTime.now());
        return labelFieldContentMapper.updateLabelFieldContent(labelFieldContent);
    }

    /**
     * 批量删除标签字段内容信息
     *
     * @param ids 需要删除的标签字段内容信息主键
     * @return 结果
     */
    @Override
    public int deleteLabelFieldContentByIds(Long[] ids) {
        return labelFieldContentMapper.deleteLabelFieldContentByIds(ids);
    }

    /**
     * 删除标签字段内容信息信息
     *
     * @param id 标签字段内容信息主键
     * @return 结果
     */
    @Override
    public int deleteLabelFieldContentById(Long id) {
        return labelFieldContentMapper.deleteLabelFieldContentById(id);
    }

    /**
     * 批量新增标签字段内容信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertLabelFieldContents(LabelFieldContentAddDTO labelFieldContentAddDTO) {
        // 获取到标签字段内容信息集合
        List<LabelFieldContentDTO> fieldContentList = labelFieldContentAddDTO.getFieldContentList();
        // 获取到标签字段信息Id
        Long fieldId = labelFieldContentAddDTO.getFieldId();
        // 检查数据库中同一个fieldId下内容名称的重复性
        for (LabelFieldContentDTO contentDTO : fieldContentList) {
            // 如果存在，报错-已存在字段内容名称
            if (labelFieldContentMapper.existCountByFieldIdAndContentName(fieldId, contentDTO.getContentName()) > 0) {
                throw new ServiceException("当前标签字段类型下字段内容名称已存在");
            }
            // 不存在，执行新增
            LabelFieldContent labelFieldContent = new LabelFieldContent();
            BeanUtils.copyProperties(contentDTO, labelFieldContent);
            labelFieldContent.setFieldId(labelFieldContentAddDTO.getFieldId());
            labelFieldContent.setFieldName(labelFieldContentAddDTO.getFieldName());
            labelFieldContent.setPortraitStatus(PortraitStatusEnum.INUSE.getInfo());
            labelFieldContent.setCreateBy(SecurityUtils.getUsername());
            labelFieldContent.setCreateTime(LocalDateTime.now());
            if (labelFieldContentMapper.insertLabelFieldContent(labelFieldContent) <= 0) {
                throw new ServiceException("新增标签字段内容信息失败");
            }
        }
        return 1;
    }

    /**
     * 分组信息
     *
     * @return LabelFieldInfo
     */
    @Override
    public AjaxResult groupingContent(Long patientId) {
        //创建全部选项 TaskPartitionDictId =0为全部
        List<LabelFieldInfo> labelFieldInfoList = new ArrayList<>();
        LabelFieldInfo labelFieldInfo = new LabelFieldInfo();
        labelFieldInfo.setTaskPartitionDictId(0L);
        labelFieldInfo.setTaskPartitionDictName("全部");
        labelFieldInfoList.add(labelFieldInfo);
        //任务细分表数据
        List<LabelFieldInfo> labelFieldInfos = labelFieldInfoMapper.taskPartitionDictIdList();
        if (CollectionUtils.isNotEmpty(labelFieldInfos)) {
            List<Long> collect = labelFieldInfos.stream().filter(Objects::nonNull).filter(item -> Objects.nonNull(item.getTaskPartitionDictId())).map(LabelFieldInfo::getTaskPartitionDictId).distinct().collect(Collectors.toList());
            List<LabelFieldContent> labelFieldContents = labelFieldContentMapper.selectLabelFieldContentPortraitSn(collect, patientId);
            if (CollectionUtils.isNotEmpty(labelFieldContents)) {
                for (LabelFieldInfo fieldInfo : labelFieldInfos) {
                    List<String> collect1 = labelFieldContents.stream().filter(Objects::nonNull).filter(item -> Objects.nonNull(item.getFieldId()) && fieldInfo.getTaskPartitionDictId().equals(item.getFieldId())).map(LabelFieldContent::getPortraitSn).distinct().collect(Collectors.toList());
                    fieldInfo.setFieldSort(collect1.size());
                }
            }
            labelFieldInfoList.addAll(labelFieldInfos);
        }
        //未分组选项  TaskPartitionDictId =null 为未分组
        LabelFieldInfo labelFieldInfoTwo = new LabelFieldInfo();
        labelFieldInfoTwo.setTaskPartitionDictName("未分组");
        labelFieldInfoList.add(labelFieldInfoTwo);
        return AjaxResult.success(labelFieldInfoList);
    }

    /**
     * 画像查询
     *
     * @param taskPartitionDictId 细分id
     * @param patientId           患者id
     * @return GroupingValue
     */
    @Override
    public List<LabelFieldAndPartitionDict> groupingValue(Long taskPartitionDictId, Long patientId) {
        if (ObjectUtils.isEmpty(patientId)) {
            throw new ServiceException("请选择患者!");
        }
        PatientTaskDto patientTaskDto = new PatientTaskDto();
        patientTaskDto.setPatientId(patientId);
        //根据患者id查询节点富文本所需标签
        List<SignPatientManageRouteNode> nodeList = signPatientManageRouteNodeMapper.getNodeList(patientTaskDto);
        List<SignPatientManageRouteNode> routeNodeContentList = signPatientManageRouteNodeMapper.getRouteNodeContentList(patientId);
        if (CollectionUtils.isNotEmpty(routeNodeContentList)) {
            nodeList.addAll(routeNodeContentList);
        }
        List<String> nodeContentList = nodeList.stream().filter(Objects::nonNull).map(SignPatientManageRouteNode::getNodeContent).filter(Objects::nonNull).collect(Collectors.toList());
        String nodeContentListJoin = String.join(",", nodeContentList);
        Document document = Jsoup.parse(nodeContentListJoin);
        // 需要提取的span
        List<String> string = new ArrayList<>();
        Elements spanList = document.select("span[data-w-e-type]");
        for (Element span : spanList) {
            String paramKey = span.attr("data-fieldMark");
            string.add(paramKey);
        }
        //根据patientId查询是否有已经维护的参数、有维护数据返回已维护数据、没有维护数据查询视图数据
        List<GroupingValue> groupingValues;
        groupingValues = labelFieldContentMapper.labelFieldAndPartitionDict(taskPartitionDictId, patientId, null);
        if (CollectionUtils.isNotEmpty(groupingValues)) {
            for (GroupingValue groupingValue : groupingValues) {
                groupingValue.setPatientId(patientId);
                List<String> collect = string.stream().filter(Objects::nonNull).filter(item -> item.equals(groupingValue.getFieldCode())).collect(Collectors.toList());
                //判断星标
                if (CollectionUtils.isNotEmpty(collect)) {
                    groupingValue.setSign(1);
                } else {
                    groupingValue.setSign(0);
                }
            }
            //组装数据
            List<Long> taskPartitionDictIds = groupingValues.stream().filter(Objects::nonNull).map(LabelFieldInfo::getTaskPartitionDictId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            List<LabelFieldAndPartitionDict> labelFieldAndPartitionDictList = new ArrayList<>();
            for (Long aLong : taskPartitionDictIds) {
                List<PortraitSnVO> PortraitSnVOS = new ArrayList<>();
                LabelFieldAndPartitionDict labelFieldAndPartitionDict = new LabelFieldAndPartitionDict();
                List<GroupingValue> collect = groupingValues.stream().filter(Objects::nonNull).filter(item -> aLong.equals(item.getTaskPartitionDictId())).collect(Collectors.toList());
                Map<String, List<GroupingValue>> collect1 = collect.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(GroupingValue::getPortraitSn));
                collect1.forEach((Key, value) -> {
                    PortraitSnVO portraitSnVO = new PortraitSnVO();
                    portraitSnVO.setPortraitSn(Key);
                    portraitSnVO.setGroupingValues(value);
                    PortraitSnVOS.add(portraitSnVO);
                });
                labelFieldAndPartitionDict.setTaskPartitionDictId(aLong);
                labelFieldAndPartitionDict.setTaskPartitionDictName(collect.get(0).getTaskPartitionDictName());
                labelFieldAndPartitionDict.setPortraitSnVOList(PortraitSnVOS);
                labelFieldAndPartitionDictList.add(labelFieldAndPartitionDict);
            }
            return labelFieldAndPartitionDictList;
        }
        //查询未维护标签及从患者表取值，患者视图无值返回分组，有值根据属性名遍历塞入
        groupingValues = labelFieldInfoMapper.selectLabelFieldInfoByTaskPartitionDictId(taskPartitionDictId);
        JSONObject paramsValue = getParamsValue(patientId);
        if (CollectionUtils.isEmpty(groupingValues)) {
            return new ArrayList<>();
        }
        //取患者表视图属性名
        PatientAllInfoView patientAllInfoView = new PatientAllInfoView();
        Field[] declaredFields = patientAllInfoView.getClass().getDeclaredFields();
        String[] strings = new String[declaredFields.length];
        for (int i = 0; i < declaredFields.length; i++) {
            strings[i] = declaredFields[i].getName().toUpperCase();
        }
        //遍历分组，根据属性名塞入视图值
        List<String> asListStrings = Arrays.asList(strings);
        for (GroupingValue groupingValue : groupingValues) {
            groupingValue.setPatientId(patientId);
            String s = asListStrings.stream().filter(Objects::nonNull).filter(item -> item.equals(groupingValue.getFieldCode())).findFirst().orElse(new String());
            List<String> collect = string.stream().filter(Objects::nonNull).filter(item -> item.equals(groupingValue.getFieldCode())).collect(Collectors.toList());
            //判断星标
            if (CollectionUtils.isNotEmpty(collect)) {
                groupingValue.setSign(1);
            } else {
                groupingValue.setSign(0);
            }
            //塞入视图数据
            groupingValue.setFieldValue(paramsValue.getOrDefault(s, "").toString());
        }
        //遍历任务细分id组装数据
        List<Long> collect = groupingValues.stream().filter(Objects::nonNull).filter(item -> Objects.nonNull(item.getTaskPartitionDictId())).map(LabelFieldInfo::getTaskPartitionDictId).distinct().collect(Collectors.toList());
        List<LabelFieldAndPartitionDict> labelFieldAndPartitionDictList = new ArrayList<>();
        for (Long aLong : collect) {
            List<PortraitSnVO> PortraitSnVOS = new ArrayList<>();
            LabelFieldAndPartitionDict labelFieldAndPartitionDict = new LabelFieldAndPartitionDict();
            PortraitSnVO portraitSnVO = new PortraitSnVO();
            List<GroupingValue> collect1 = groupingValues.stream().filter(Objects::nonNull).filter(item -> aLong.equals(item.getTaskPartitionDictId())).collect(Collectors.toList());
            portraitSnVO.setGroupingValues(collect1);
            PortraitSnVOS.add(portraitSnVO);
            labelFieldAndPartitionDict.setTaskPartitionDictId(aLong);
            labelFieldAndPartitionDict.setTaskPartitionDictName(collect1.get(0).getTaskPartitionDictName());
            labelFieldAndPartitionDict.setPortraitSnVOList(PortraitSnVOS);
            labelFieldAndPartitionDictList.add(labelFieldAndPartitionDict);
        }
        return labelFieldAndPartitionDictList;
    }

    /**
     * 画像内容新增
     *
     * @param labelField 画像信息
     * @return AjaxResult
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult insertLabelField(LabelField labelField) {
        if (CollectionUtils.isEmpty(labelField.getLabelFieldAndPartitionDictList())) {
            return AjaxResult.success();
        }
        List<PortraitSnVO> PortraitSnVOS = new ArrayList<>();
        List<GroupingValue> groupingValues = new ArrayList<>();
        for (LabelFieldAndPartitionDict labelFieldAndPartitionDict : labelField.getLabelFieldAndPartitionDictList()) {
            if (CollectionUtils.isNotEmpty(labelFieldAndPartitionDict.getPortraitSnVOList())) {
                PortraitSnVOS.addAll(labelFieldAndPartitionDict.getPortraitSnVOList());
            }
        }
        if (CollectionUtils.isEmpty(PortraitSnVOS)) {
            return AjaxResult.success();
        }
        try {
            for (PortraitSnVO portraitSnVO : PortraitSnVOS) {
                if (StringUtils.isBlank(portraitSnVO.getPortraitSn())) {
                    portraitSnVO.setPortraitSn(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")));
                    portraitSnVO.getGroupingValues().forEach(item -> item.setPortraitSn(portraitSnVO.getPortraitSn()));
                    portraitSnVO.getGroupingValues().forEach(item -> item.setLabelFieldContentId(null));
                }
                groupingValues.addAll(portraitSnVO.getGroupingValues());
                TimeUnit.MILLISECONDS.sleep(10);
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        List<GroupingValue> updateGroupingValues = new ArrayList<>();
        List<GroupingValue> insertGroupingValues = new ArrayList<>();
        //传入标签ids
        List<Long> afferentLabelFieldInfoIds = groupingValues.stream().filter(Objects::nonNull).map(GroupingValue::getLabelFieldInfoId).filter(Objects::nonNull).collect(Collectors.toList());
        //传入标签内容ids
        List<Long> afferentLabelFieldContentIds = groupingValues.stream().filter(Objects::nonNull).map(GroupingValue::getLabelFieldContentId).filter(Objects::nonNull).collect(Collectors.toList());
        //数据库标签内容ids
        List<LabelFieldContentVO> databaseLabelFieldContents = labelFieldContentMapper.selectLabelFieldContent(afferentLabelFieldInfoIds, groupingValues.get(0).getPatientId());
        List<Long> databaseLabelFieldContentIds = databaseLabelFieldContents.stream().filter(Objects::nonNull).map(LabelFieldContentVO::getLabelFieldContentId).filter(Objects::nonNull).collect(Collectors.toList());
        //做差集
        List<Long> subtractLabelFieldContentIds = (List<Long>) CollectionUtils.subtract(databaseLabelFieldContentIds, afferentLabelFieldContentIds);
        if (CollectionUtils.isNotEmpty(subtractLabelFieldContentIds)) {
            labelFieldContentMapper.deleteLabelFieldContentByIds(subtractLabelFieldContentIds.toArray(new Long[0]));
        }
        for (GroupingValue groupingValue : groupingValues) {
            groupingValue.setFieldId(groupingValue.getLabelFieldInfoId());
            if (Objects.isNull(groupingValue.getLabelFieldContentId())) {
                groupingValue.setCreateBy(SecurityUtils.getUsername());
                groupingValue.setCreateTime(LocalDateTime.now());
                groupingValue.setPortraitStatus(PortraitStatusEnum.INUSE.getInfo());
                insertGroupingValues.add(groupingValue);
            }
            if (Objects.nonNull(groupingValue.getLabelFieldContentId())) {
                groupingValue.setUpdateTime(LocalDateTime.now());
                groupingValue.setUpdateBy(SecurityUtils.getUsername());
                groupingValue.setPortraitStatus(PortraitStatusEnum.INUSE.getInfo());
                updateGroupingValues.add(groupingValue);
            }
        }
        if (CollectionUtils.isNotEmpty(insertGroupingValues)) {
            int insert = labelFieldContentMapper.insertLabelFieldContentList(insertGroupingValues);
        }
        if (CollectionUtils.isNotEmpty(updateGroupingValues)) {
            int update = labelFieldContentMapper.updateContentRemarkLabelFieldContentList(updateGroupingValues);
        }
        return AjaxResult.success();
    }

    /**
     * 根据任务细分类型获取患者的真实信息
     *
     * @param patientId 患者主键
     * @return 实际信息
     */
    private JSONObject getParamsValue(Long patientId) {
        JSONObject retObj;
        List<PatientAllInfoViewUppercase> patientAllInfoViews = patientAllInfoViewMapper.selectPatientAllInfoListViewByPatientId(patientId);
        if (CollectionUtils.isEmpty(patientAllInfoViews) || ObjectUtils.isEmpty(patientAllInfoViews.get(0))) {
            throw new ServiceException("患者信息获取错误，请联系管理员!");
        }
        PatientAllInfoViewUppercase patientAllInfoView = patientAllInfoViews.get(0);
        retObj = JSONObject.parseObject(JSONObject.toJSONString(patientAllInfoView));
        try {
            // 性别转换成中文、计算年龄
            retObj.fluentPut("SEX", PatientSexEnum.getInfoByCode(patientAllInfoView.getSEX()).getInfo()).fluentPut("AGE", BaseUtil.getAge(patientAllInfoView.getBIRTHDATE()));
        }
        catch(Exception ex) {}
        return retObj;
    }
}
