package com.openhis.web.inpatientmanage.appservice.impl;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.BiConsumer;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
import com.core.common.core.domain.entity.SysUser;
import com.core.common.core.domain.model.LoginUser;
import com.core.common.utils.MessageUtils;
import com.core.common.utils.SecurityUtils;
import com.core.common.utils.TimeUtils;
import com.core.common.utils.bean.BeanUtils;
import com.openhis.common.constant.PromptMsgConstant;
import com.openhis.common.enums.EncounterClass;
import com.openhis.common.enums.EventStatus;
import com.openhis.common.utils.EnumUtils;
import com.openhis.common.utils.HisQueryUtils;
import com.openhis.document.domain.VitalSigns;
import com.openhis.document.service.IVitalSignsService;
import com.openhis.web.inpatientmanage.appservice.IVitalSignsAppService;
import com.openhis.web.inpatientmanage.dto.*;
import com.openhis.web.inpatientmanage.mapper.VitalSignsAppMapper;

/**
 * 三测单 实现类
 *
 * @author SY
 * @since 2025/05/29
 */
@Service
public class VitalSignsAppServiceImpl implements IVitalSignsAppService {

    @Resource
    private VitalSignsAppMapper vitalSignsAppMapper;

    @Resource
    private IVitalSignsService vitalSignsService;

    /**
     * 三测单-患者信息查询
     *
     * @return 三测单-患者信息数据列表
     */
    @Override
    public R<?> getVitalSignsInfo(VitalSignsSearchParam vitalSignsSearchParam, String searchKey, Integer pageNo,
        Integer pageSize, HttpServletRequest request) {

        // 构建查询条件
        QueryWrapper<VitalSignsDto> queryWrapper =
            HisQueryUtils.buildQueryWrapper(vitalSignsSearchParam, searchKey, new HashSet<>(), request);

        // 分页查询,查询患者信息
        IPage<VitalSignsDto> vitalSignsInfoPage = vitalSignsAppMapper.getVitalSignsInfo(new Page<>(pageNo, pageSize),
            vitalSignsSearchParam.getPatientId(), searchKey, queryWrapper);

        VitalSignsMedicalRecordDto medicalRecord = new VitalSignsMedicalRecordDto();

        // 处理日期
        if (!vitalSignsInfoPage.getRecords().isEmpty()) {
            medicalRecord.setHospDate(vitalSignsInfoPage.getRecords().get(0).getRecordingDate());
        }

        // 处理生命体征数据
        Map<Integer, VitalSignsTemperaturePulsesDto> groupMap = new HashMap<>();
        List<VitalSignsDto> vitalSignsInfoPageList = vitalSignsInfoPage.getRecords();

        vitalSignsInfoPageList.forEach(item -> {

            // 就诊类别
            item.setClassEnum_enumText(EnumUtils.getInfoByValue(EncounterClass.class, item.getClassEnum()));

            // 手术状态
            item.setSurgeryStatusEnum_enumText(
                EnumUtils.getInfoByValue(EventStatus.class, item.getSurgeryStatusEnum()));

            // 计算完整周数
            if (item.getClassEnum() == EncounterClass.IMP.getValue()) {
                // 转换为 LocalDate 进行日期计算
                LocalDate admissionDate = TimeUtils.dateToLocalDate(item.getAdmissionDate());
                LocalDate recordingDate = TimeUtils.dateToLocalDate(item.getRecordingDate());

                // 计算天数差
                long dayDiff = ChronoUnit.DAYS.between(admissionDate, recordingDate);
                int hospitalizationDays = (int)(dayDiff + 1);
                item.setHospitalizationDays(hospitalizationDays);

                // 计算周数（向上取整）
                int weekNo = (hospitalizationDays + 6) / 7;
                item.setWeekNo(weekNo);
            }

            // 计算术后天数
            // 手术已完成的患者
            if (item.getSurgeryStatusEnum() == EventStatus.COMPLETED.getValue()) {
                if (item.getSurgeryStartTime() != null && item.getSurgeryEndTime() != null) {
                    // 手术结束时间的类型转换
                    LocalDate endTime = TimeUtils.dateToLocalDate(item.getSurgeryEndTime());
                    // 记录日期的类型转换
                    LocalDate recordingtime = TimeUtils.dateToLocalDate(item.getRecordingDate());
                    // 术后天数计算
                    int surgeryDays = (int)ChronoUnit.DAYS.between(endTime, recordingtime);
                    // 设置术后天数
                    item.setPostoperativeDays(surgeryDays);
                }
            }
            Integer weekNo = item.getWeekNo();
            VitalSignsTemperaturePulsesDto group = groupMap.computeIfAbsent(weekNo, k -> {
                VitalSignsTemperaturePulsesDto newGroup = new VitalSignsTemperaturePulsesDto();
                newGroup.setWeekNo(weekNo);
                return newGroup;
            });

            // 格式化时间
            Date recordingDate = item.getRecordingDate();
            String dateStr = TimeUtils.dateToDateString(recordingDate);
            Date timePoint = item.getTimePoint();
            String timeStr = TimeUtils.dateToTimeString(timePoint);

            // 体温单列表做成
            VitalSignsChartSmallDto chartSmall = new VitalSignsChartSmallDto();
            chartSmall.setCollectionMode(2);
            chartSmall.setDate(dateStr);
            chartSmall.setTimes(timeStr);
            chartSmall.setTypeCode(item.getVitalSignsCode());
            chartSmall.setTypeValue(item.getVitalSignsValues());
            chartSmall.setWeekNo(weekNo);
            chartSmall.setPostoperativeDays(item.getPostoperativeDays());
            group.getChartsSmalls().add(chartSmall);
            group.setWeekNo(weekNo);
        });

        medicalRecord.setTemperaturePulses(new ArrayList<>(groupMap.values()));

        // 返回【患者信息列表DTO】分页
        return R.ok(medicalRecord);
    }

    /**
     * 体温单记录保存
     *
     * @param vitalSignsSaveDto 患者体征信息
     * @return 保存结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<?> saveVitalSigns(VitalSignsSaveDto vitalSignsSaveDto) {
        // 参数校验
        if (vitalSignsSaveDto == null) {
            return R.fail("生命体征记录不能为空");
        }

        // 获取当前登录用户
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null) {
            return R.fail("未获取到登录用户信息");
        }
        SysUser user = loginUser.getUser();
        List<VitalSigns> vitalSignsList = new ArrayList<>();

        // 解析时间点
        LocalTime timePoint = TimeUtils.parseTime(vitalSignsSaveDto.getTimePoint());
        if (timePoint == null) {
            return R.fail("时间格式解析失败");
        }

        // 创建基础生命体征记录
        VitalSigns baseRecord = new VitalSigns();
        baseRecord.setPatientId(vitalSignsSaveDto.getPatientId()).setEncounterId(vitalSignsSaveDto.getEncounterId())
            .setRecordingDate(vitalSignsSaveDto.getRecordingDate()).setTimePoint(TimeUtils.localTimeToDate(timePoint))
            .setLocationId(vitalSignsSaveDto.getLocationId()).setRecorder(user.getUserName())
            .setRemake(vitalSignsSaveDto.getRemake());

        // 使用反射获取所有生命体征字段
        Field[] fields = VitalSignsSaveDto.class.getDeclaredFields();
        for (Field field : fields) {
            // 通过注解判断是否为生命体征字段
            VitalSignsField vitalSignsField = field.getAnnotation(VitalSignsField.class);
            if (vitalSignsField == null) {
                continue; // 跳过非生命体征字段
            }

            // 设置字段可访问
            field.setAccessible(true);

            try {
                // 获取字段值
                Object fieldValue = field.get(vitalSignsSaveDto);
                if (fieldValue == null) {
                    continue; // 跳过null值
                }

                String value;
                if (fieldValue instanceof String) {
                    value = (String)fieldValue;
                    if (value.trim().isEmpty()) {
                        continue; // 跳过空字符串
                    }
                } else {
                    value = fieldValue.toString(); // 其他类型转换为字符串
                }

                // 校验生命体征编码
                String code = vitalSignsField.code();
                if (code == null || code.isEmpty()) {
                    continue;
                }

                // 获取单位
                String unit = vitalSignsField.unit();
                if (unit == null || unit.isEmpty()) {
                    continue;
                }

                // 构建生命体征记录
                VitalSigns record = cloneVitalSignsRecord(baseRecord);
                record.setVitalSignsCode(code);
                record.setVitalSignsValues(value);
                record.setUnits(unit);

                vitalSignsList.add(record);

            } catch (IllegalAccessException | ClassCastException e) {
                return R.fail("生命体征数据格式错误");
            }
        }

        if (vitalSignsList.isEmpty()) {
            return R.fail("未检测到有效的生命体征数据");
        }

        // 检查记录是否已存在
        boolean existingRecordCount = vitalSignsService.selectBatchVitalSigns(vitalSignsList);

        // 存在
        if (existingRecordCount) {
            // 原纪录删除
            vitalSignsAppMapper.deleteVitalSigns(vitalSignsList.get(0).getPatientId(),
                vitalSignsList.get(0).getEncounterId(), vitalSignsList.get(0).getRecordingDate(),
                vitalSignsList.get(0).getTimePoint());
        }
        boolean saveResult = vitalSignsService.saveOrUpdateBatchVitalSigns(vitalSignsList);

        return saveResult ? R.ok("保存成功") : R.fail("保存失败");
    }

    /**
     * 患者体温单检索
     *
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 检索结果
     */
    @Override
    public R<?> searchVitalSigns(String startTime, String endTime) {

        // 基本信息查询
        List<VitalSigns> vitalSignsList = vitalSignsAppMapper.searchVitalSigns(startTime, endTime);
        // 判断查询结果是否为空
        if (vitalSignsList.isEmpty()) {
            return R.ok(Collections.emptyList());
        }

        // 创建属性映射表
        Map<String, BiConsumer<VitalSignSearchRecordDto, String>> propertySetterMap =
            createPropertySetterMapUsingReflection();

        // 按日期时间分组处理数据
        List<VitalSignSearchRecordDto> resultList = new ArrayList<>();
        VitalSignSearchRecordDto currentRecord = null;
        String currentDateTimeKey = null;

        for (VitalSigns item : vitalSignsList) {
            // 生成日期时间键
            String dateStr = TimeUtils.dateToDateString(item.getRecordingDate());
            String timeStr = TimeUtils.dateToTimeString(item.getTimePoint());
            String dateTimeKey = dateStr + " " + timeStr;

            // 如果日期时间变化，创建新记录
            if (!dateTimeKey.equals(currentDateTimeKey)) {
                if (currentRecord != null && isRecordValid(currentRecord)) {
                    resultList.add(currentRecord);
                }
                currentRecord = new VitalSignSearchRecordDto();
                currentDateTimeKey = dateTimeKey;

                // 设置日期时间
                currentRecord.setRecordingDate(dateStr);
                currentRecord.setTimePoint(timeStr);
            }

            // 获取代码对应的字段
            String fieldName =
                AnnotationConverter.getFieldNameByCode(VitalSignSearchRecordDto.class, item.getVitalSignsCode());
            // 设置生命体征值
            BiConsumer<VitalSignSearchRecordDto, String> setter = propertySetterMap.get(fieldName);
            if (setter != null) {
                setter.accept(currentRecord, item.getVitalSignsValues());
            }
        }

        // 添加最后一条记录
        if (currentRecord != null && isRecordValid(currentRecord)) {
            resultList.add(currentRecord);
        }

        return R.ok(resultList);
    }

    /**
     * 体温单记录删除
     *
     * @param vitalSignsDeleteDto 患者体征信息
     * @return 删除结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<?> deleteVitalSigns(List<VitalSignsDeleteDto> vitalSignsDeleteDto) {

        List<VitalSigns> vitalSignsList = new ArrayList<>();

        for (VitalSignsDeleteDto deleteDto : vitalSignsDeleteDto) {

            // 记录日期的格式化
            LocalDateTime recordDateTime = TimeUtils.parseDateTime(deleteDto.getRecordingDate());
            Date date = Date.from(recordDateTime.atZone(ZoneId.systemDefault()).toInstant());

            // 记录时间的格式化
            LocalDateTime timePoint =
                TimeUtils.parseDateTime(deleteDto.getRecordingDate().substring(0, 11) + deleteDto.getTimePoint());
            Date time = Date.from(timePoint.atZone(ZoneId.systemDefault()).toInstant());

            VitalSigns vitalSigns = new VitalSigns();
            // 设置患者ID
            vitalSigns.setPatientId(deleteDto.getPatientId())
                // 设置就诊ID
                .setEncounterId(deleteDto.getEncounterId())
                // 设置记录日期
                .setRecordingDate(date)
                // 设置记录时间
                .setTimePoint(time);

            vitalSignsList.add(vitalSigns);
            // 确认删除的数据是否存在
            boolean existingRecord = vitalSignsService.selectBatchVitalSigns(vitalSignsList);

            // 数据不存在
            if (!existingRecord) {
                return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00006, null));
            } else {
                // 数据存在(删除记录)
                vitalSignsAppMapper.deleteVitalSigns(deleteDto.getPatientId(), deleteDto.getEncounterId(), date, time);
            }
        }
        return R.ok(null);
    }

    // 克隆生命体征记录对象
    private VitalSigns cloneVitalSignsRecord(VitalSigns baseRecord) {
        try {
            // 序列化方式实现深拷贝
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(baseRecord);

            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            return (VitalSigns)ois.readObject();
        } catch (Exception e) {
            // 浅拷贝作为降级方案
            VitalSigns record = new VitalSigns();
            BeanUtils.copyProperties(baseRecord, record);
            return record;
        }
    }

    // 使用反射自动生成属性映射表
    private Map<String, BiConsumer<VitalSignSearchRecordDto, String>> createPropertySetterMapUsingReflection() {
        Map<String, BiConsumer<VitalSignSearchRecordDto, String>> map = new HashMap<>();

        // 获取所有方法
        Method[] methods = VitalSignSearchRecordDto.class.getMethods();

        // 遍历方法，筛选出符合条件的setter
        for (Method method : methods) {
            String methodName = method.getName();

            // 判断是否为setter方法：以"set"开头，有一个参数
            if (methodName.startsWith("set") && method.getParameterCount() == 1) {
                // 获取属性名
                String propertyName = methodName.substring(3); // 去掉"set"前缀
                if (propertyName.length() > 0) {
                    // 将属性名首字母小写
                    propertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1);

                    // 参数类型检查：确保参数类型是String或可以转换为String
                    Class<?> paramType = method.getParameterTypes()[0];
                    if (paramType == String.class) {
                        // 使用方法引用创建BiConsumer
                        BiConsumer<VitalSignSearchRecordDto, String> setter = (obj, value) -> {
                            try {
                                method.invoke(obj, value);
                            } catch (Exception e) {
                                throw new RuntimeException("设置属性值失败");
                            }
                        };

                        map.put(propertyName, setter);
                    }
                }
            }
        }
        return map;
    }

    // 转换工具类
    public class AnnotationConverter {
        // 根据代码查找对应的字段名
        public static String getFieldNameByCode(Class<?> clazz, String code) {
            for (Field field : clazz.getDeclaredFields()) {
                VitalSignsField annotation = field.getAnnotation(VitalSignsField.class);
                if (annotation != null && annotation.code().equals(code)) {
                    return annotation.name();
                }
            }
            return "未知代码";
        }

        // 根据字段名查找对应的代码
        public static String getCodeByFieldName(Class<?> clazz, String fieldName) {
            for (Field field : clazz.getDeclaredFields()) {
                VitalSignsField annotation = field.getAnnotation(VitalSignsField.class);
                if (annotation != null && annotation.name().equals(fieldName)) {
                    return annotation.code();
                }
            }
            return "未知名称";
        }
    }

    // 有效性检查
    private boolean isRecordValid(VitalSignSearchRecordDto record) {
        // 检查所有可能的属性
        return record.getSystolicPressure() != null || record.getDiastolicPressure() != null
            || record.getTemperature() != null || record.getHeartRate() != null || record.getPulseRate() != null
            || record.getBloodOxygen() != null || record.getBloodGlucose() != null
            || record.getPhysicalCooling() != null || record.getCcuHeartRate() != null
            || record.getNewbornsIncubator() != null || record.getBloodKetone() != null || record.getHeight() != null
            || record.getWaistCircumference() != null || record.getStoolFrequency() != null
            || record.getEnemaFrequency() != null || record.getSfAfterEnema() != null || record.getOutput() != null
            || record.getInput() != null || record.getUrineVolume() != null || record.getStoolVolume() != null;
    }
}
