package com.emoon.chat.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.emoon.chat.domain.MedicalRecordResult;
import com.emoon.chat.domain.MedicalRecordView;
import com.emoon.chat.domain.PatientRecord;
import com.emoon.chat.domain.dto.PatientRecordWithQCResultDTO;
import com.emoon.chat.domain.dto.RecordDetailItemDTO;
import com.emoon.chat.mapper.MedicalRecordResultMapper;
import com.emoon.chat.mapper.MedicalRecordViewMapper;
import com.emoon.chat.mapper.PatientRecordMapper;
import com.emoon.chat.service.IPatientRecordService;
import com.emoon.chat.utils.HttpUtils;
import com.emoon.common.mybatis.core.page.PageQuery;
import com.emoon.common.mybatis.core.page.TableDataInfo;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSON;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class PatientRecordServiceImpl implements IPatientRecordService {
    @Resource
    private PatientRecordMapper patientRecordMapper;
    @Resource
    private MedicalRecordResultMapper medicalRecordResultMapper;
    @Resource
    private MedicalRecordViewMapper medicalRecordViewMapper;

    private final ObjectMapper objectMapper = new ObjectMapper();
    private static final Pattern RECORD_DATETIME_PREFIX = Pattern.compile("^(\\d{4}-\\d{2}-\\d{2}[ T]\\d{2}:\\d{2}(?::\\d{2})?)");

    // 接口地址
    private static final String FETCH_URL = "http://192.168.0.155:35293/api/EMoon/DischargeEmrContent";
    private  String url = "https://mock.apipost.net/mock/4efc7a2f0469000/api/EMoon/DischargeEmrContent?apipost_id=2fc7a7fa3bc005";

    /**
     * 使用 HttpUtils 发起 GET 请求，获取数据并存入数据库
     */
    public void fetchAndSavePatientTest() {
        try {
            // 1. 使用你自己的 HttpUtils 发起 GET 请求
            String jsonResponse = HttpUtils.sendHttpGet(url);

            if (jsonResponse == null || jsonResponse.isEmpty()) {
                System.err.println("❌ HTTP 请求返回空数据");
                return;
            }

            // 2. 手动解析 JSON（使用 Jackson）
            Map<String, Object> responseMap = objectMapper.readValue(jsonResponse, Map.class);

            Integer code = (Integer) responseMap.get("code");
            if (code == null || code != 1) {
                System.err.println("❌ 接口返回 code 不为1，返回内容：" + jsonResponse);
                return;
            }

            List<Map<String, Object>> dataList = (List<Map<String, Object>>) responseMap.get("data");
            if (dataList == null || dataList.isEmpty()) {
                System.out.println("📭 接口返回 data 为空");
                return;
            }

            // 3. 转换为 PatientRecord 列表
            List<PatientRecord> recordsToSave = new ArrayList<>();
            for (Map<String, Object> item : dataList) {
                PatientRecord record = convertToPatientRecord(item);
                if (record != null) {
                    recordsToSave.add(record);
                }
            }

            // 4. 批量插入数据库
            if (!recordsToSave.isEmpty()) {
                boolean result = patientRecordMapper.insertBatchSomeColumn(recordsToSave);
                if (result) {
                    System.out.println("✅ 成功保存 " + recordsToSave.size() + " 条患者数据");
                } else {
                    System.err.println("❌ 数据库插入失败");
                }
            }

        } catch (Exception e) {
            System.err.println("❌ 请求或保存数据时发生异常: " + e.getMessage());
            e.printStackTrace();
        }
    }
    @Override
    public void fetchAndSavePatientData(String startDate, String endDate) {
        try {
            // 1. 构造 JSON 参数
            ObjectMapper objectMapper = new ObjectMapper(); // 假设你已有实例，否则可注入或复用
            ObjectNode jsonNode = objectMapper.createObjectNode();
            jsonNode.put("startDate", startDate);
            jsonNode.put("endDate", endDate);
            String jsonParam = objectMapper.writeValueAsString(jsonNode);

            // 2. 使用你的工具类发送 POST 请求（JSON 格式）
            String jsonResponse = HttpUtils.sendHttpPostByJson(FETCH_URL, jsonParam);

            if (jsonResponse == null || jsonResponse.isEmpty()) {
                System.err.println("❌ HTTP 请求返回空数据");
                return;
            }

            // 3. 解析响应（假设返回格式不变）
            Map<String, Object> responseMap = objectMapper.readValue(jsonResponse, Map.class);

            Integer code = (Integer) responseMap.get("code");
            if (code == null || code != 1) {
                System.err.println("❌ 接口返回 code 不为1，返回内容：" + jsonResponse);
                return;
            }

            List<Map<String, Object>> dataList = (List<Map<String, Object>>) responseMap.get("data");
            if (dataList == null || dataList.isEmpty()) {
                System.out.println("📭 接口返回 data 为空");
                return;
            }

            // 4. 转换为 PatientRecord 列表
            List<PatientRecord> recordsToSave = new ArrayList<>();
            for (Map<String, Object> item : dataList) {
                PatientRecord record = convertToPatientRecord(item);
                if (record != null) {
                    recordsToSave.add(record);
                }
            }

            // 5. 批量插入数据库
            if (!recordsToSave.isEmpty()) {
                boolean result = patientRecordMapper.insertBatchSomeColumn(recordsToSave);
                if (result) {
                    System.out.println("✅ 成功保存 " + recordsToSave.size() + " 条患者数据");
                } else {
                    System.err.println("❌ 数据库插入失败");
                }
            }

        } catch (Exception e) {
            System.err.println("❌ 请求或保存数据时发生异常: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 将 Map<String, Object> 转换为 PatientRecord 实体
     */
    @SuppressWarnings("unchecked")
    private PatientRecord convertToPatientRecord(Map<String, Object> data) {
        try {
            PatientRecord record = new PatientRecord();

            // ✅ STEP 1: 设置所有可能为空的 JSON 字段的默认值为 "[]"
            // 这样即使后续没有数据，也会存入 [] 而不是 null
            record.setCourseRecords("[]");
            record.setStageSummary("[]");
            record.setWardRounds("[]");
            record.setConsultationRecords("[]");
            record.setDifficultCaseDiscussion("[]");
            record.setLongStayDiscussion("[]");
            record.setDeathCaseDiscussion("[]");
            record.setRescueRecords("[]");
            record.setSurgeryRecords("[]");
            record.setLabReports("[]");
            record.setExamReports("[]");
            record.setConsentForms("[]");
            record.setOrders("[]"); // ✅ 也给 orders 设置默认值


            record.setId(UUID.randomUUID().toString());
            // 使用雪花ID（需要引入雪花ID工具类）：
            // record.setId(String.valueOf(IdWorker.getId())); // MyBatis-Plus内置
            // 或者：record.setId(IdUtils.snowflakeId()); // 若项目有自定义工具类
            record.setPatientId(getString(data, "patientId"));
            record.setVisitId(getString(data, "visitId"));
            record.setAdmissionNo(getString(data, "admissionNo"));
            record.setName(getString(data, "name", "未知"));
            record.setGender(getString(data, "gender", "未知"));
            record.setNurse(getString(data, "nurse"));
            record.setAttendingDoctor(getString(data, "attendingDoctor"));
            record.setAdmissionDept(getString(data, "admissionDept"));
            record.setDischargeDept(getString(data, "dischargeDept"));

            // 年龄
            String ageStr = getString(data, "age");
            if (ageStr != null) {
                try {
                    int ageNum = Integer.parseInt(ageStr.replaceAll("\\D+", ""));
                    record.setAge(ageNum);
                } catch (Exception e) {
                    record.setAge(0);
                }
            }

            // 日期
            record.setBirthDate(parseDateTime(getString(data, "birthDate")));
            record.setAdmissionDate(parseDateTime(getString(data, "admissionDate")));
            record.setDischargeDate(parseDateTime(getString(data, "dischargeDate")));

            // 文档分类（分字段）
            List<String> courseRecords = new ArrayList<>();
            List<String> stageSummary = new ArrayList<>();
            List<String> wardRounds = new ArrayList<>();
            List<String> consultationRecords = new ArrayList<>();
            List<String> difficultCaseDiscussion = new ArrayList<>();
            List<String> longStayDiscussion = new ArrayList<>();
            List<String> deathCaseDiscussion = new ArrayList<>();
            List<String> rescueRecords = new ArrayList<>();
            List<String> surgeryRecords = new ArrayList<>();
            List<String> labReports = new ArrayList<>();
            List<String> examReports = new ArrayList<>();
            List<String> consentForms = new ArrayList<>();

            Object emrDocsObj = data.get("emrDocs");
            if (emrDocsObj instanceof List) {
                List<Map<String, Object>> emrDocs = (List<Map<String, Object>>) emrDocsObj;

                for (Map<String, Object> doc : emrDocs) {
                    String subDocTitle = getString(doc, "subDocTitle", "");
                    String contentText = getString(doc, "contentText", "");
                    String docTitle = getString(doc, "docTitle", "");
                    String editor = getString(doc, "editor", "");

                    if ((subDocTitle.contains("入院志") || subDocTitle.contains("入院记录"))
                        && record.getAdmissionNote() == null) {
                        record.setAdmissionNote(contentText);
                    } else if (subDocTitle.contains("首次病程") && record.getFirstCourseRecord() == null) {
                        record.setFirstCourseRecord(contentText);
                    } else if (subDocTitle.contains("病程记录")) {
                        courseRecords.add(contentText);
                    } else if (subDocTitle.contains("阶段小结")) {
                        stageSummary.add(contentText);
                    } else if (subDocTitle.contains("查房记录")) {
                        wardRounds.add(contentText);
                    } else if (subDocTitle.contains("会诊记录")) {
                        consultationRecords.add(contentText);
                    } else if (subDocTitle.contains("疑难病例讨论")) {
                        difficultCaseDiscussion.add(contentText);
                    } else if (subDocTitle.contains("超长住院讨论")) {
                        longStayDiscussion.add(contentText);
                    } else if (subDocTitle.contains("死亡病例讨论")) {
                        deathCaseDiscussion.add(contentText);
                    } else if (subDocTitle.contains("抢救记录")) {
                        rescueRecords.add(contentText);
                    } else if (subDocTitle.matches(".*(手术记录|麻醉记录).*")) {
                        surgeryRecords.add(contentText);
                    } else if (subDocTitle.contains("检验")) {
                        labReports.add(contentText);
                    } else if (subDocTitle.contains("检查")) {
                        examReports.add(contentText);
                    } else if (subDocTitle.contains("出院记录") && record.getDischargeSummary() == null) {
                        record.setDischargeSummary(contentText);
                    } else if (docTitle.matches(".*(同意书|告知书|通知书).*")) {
                        consentForms.add(contentText);
                    }
                }
            }

            // 落库 JSON
            record.setCourseRecords(toJson(courseRecords));
            record.setStageSummary(toJson(stageSummary));
            record.setWardRounds(toJson(wardRounds));
            record.setConsultationRecords(toJson(consultationRecords));
            record.setDifficultCaseDiscussion(toJson(difficultCaseDiscussion));
            record.setLongStayDiscussion(toJson(longStayDiscussion));
            record.setDeathCaseDiscussion(toJson(deathCaseDiscussion));
            record.setRescueRecords(toJson(rescueRecords));
            record.setSurgeryRecords(toJson(surgeryRecords));
            record.setLabReports(toJson(labReports));
            record.setExamReports(toJson(examReports));
            record.setConsentForms(toJson(consentForms));


            // orders 处理：提取指定字段并构造成可读字符串
            Object ordersObj = data.get("orders");
            List<String> orderStrings = new ArrayList<>();

            if (ordersObj instanceof List<?>) {
                List<Map<String, Object>> ordersList = (List<Map<String, Object>>) ordersObj;
                for (Map<String, Object> order : ordersList) {
                    try {
                        // === 1️⃣ 提取主要字段 ===
                        String content = getString(order, "content", "未知医嘱");
                        String execStartTime = getString(order, "execStartTime", "");
                        String execStopTime = getString(order, "execStopTime", "");
                        String orderDoctor = getString(order, "orderDoctor", "未知医生");
                        String stopOrderDoctor = getString(order, "stopOrderDoctor", "无");
                        String execDept = getString(order, "execDept", "未知科室");
                        String status = getString(order, "status", "未知状态");
                        String orderType = getString(order, "orderType", "未知类型");
                        String medicalType = getString(order, "medicalType", "");
                        String execFrequency = getString(order, "execFrequency", "未知频率");

                        // === 2️⃣ 时间解析与格式化 ===
                        LocalDateTime startDt = parseDateTime(execStartTime);
                        LocalDateTime endDt = parseDateTime(execStopTime);

                        String startShort = (startDt != null)
                            ? startDt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
                            : "未知开始时间";
                        String stopShort = (endDt != null)
                            ? endDt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
                            : "暂无结束时间";

                        // === 3️⃣ 组装格式化输出 ===
                        String orderStr = String.format(
                            "%s（类型：%s，状态：%s，医嘱分类：%s，频率：%s，执行时间：%s ~ %s，开嘱医生：%s，停嘱医生：%s，执行科室：%s）",
                            content,
                            orderType,
                            status,
                            medicalType,
                            execFrequency,
                            startShort,
                            stopShort,
                            orderDoctor,
                            stopOrderDoctor,
                            execDept
                        );

                        orderStrings.add(orderStr);

                    } catch (Exception e) {
                        System.err.println("⚠️ 解析单条 order 失败: " + e.getMessage());
                    }
                }
            } else {
                System.err.println("⚠️ orders 字段不是列表类型或为空");
            }


            // 将字符串列表转为 JSON 存入 record
            record.setOrders(toJson(orderStrings));

            record.setStatus(1);
            record.setCreateDate(LocalDateTime.now());

            return record;
        } catch (Exception e) {
            System.err.println("❌ 转换单条记录失败: " + e.getMessage());
            return null;
        }
    }


    /**
     * 去掉 XML 标签，只保留纯文本
     */
    public static String stripXml(String xml) {
        if (xml == null || xml.isEmpty()) {
            return "";
        }

        String text = xml;

        // 1. 手动解码常见 HTML 实体（替代 StringEscapeUtils）
        text = text.replace("&lt;", "<")
            .replace("&gt;", ">")
            .replace("&amp;", "&")
            .replace("&quot;", "\"")
            .replace("&#10;", "\n")   // 换行符
            .replace("&#13;", "\r")   // 回车符
            .replace("&nbsp;", " ");  // 空格

        // 2. 处理 <signature> 标签：替换为固定文本，删除原内容
        text = text.replaceAll("(?i)<signature[^>]*>.*?</signature>", "\n经治医师:");

        // 3. 处理 <section title="...">：提取 title 并格式化为 “\n标题：内容”
        Pattern sectionPattern = Pattern.compile(
            "(?i)<section[^>]+title=[\"']([^\"']*)[\"'][^>]*>(.*?)</section>",
            Pattern.DOTALL
        );
        Matcher matcher = sectionPattern.matcher(text);
        StringBuffer result = new StringBuffer();

        while (matcher.find()) {
            String title = matcher.group(1).trim();  // 提取 title
            String content = matcher.group(2).trim(); // 提取内容

            // 清理 content 中的 utext、element 标签（只留文本）
            content = content.replaceAll("<utext>|</utext>", "")  // 移除 utext 标签
                .replaceAll("<element[^>]*>|</element>", "")  // 移除 element 标签
                .replaceAll("<e_enum[^>]*>|</e_enum>", "");  // 移除 e_enum 标签

            // 将标题和内容通过换行符连接
            String replacement = "\n" + title + "：" + content;
            matcher.appendReplacement(result, Matcher.quoteReplacement(replacement));
        }
        matcher.appendTail(result);
        text = result.toString();

        // 4. 删除所有剩余的 XML/HTML 标签
        text = text.replaceAll("<[^>]+>", "");

        // 5. 清理多余空白和标点
        // 1) 先保留换行符，合并多个换行符
        text = text.replaceAll("\n+", "\n");

        // 2) 合并多个空格和其他空白字符，忽略换行符
        text = text.replaceAll("[^\n\\S]+", " "); // 合并多个空白字符（除了换行符）

        // 3) 合并多个冒号为一个冒号
        text = text.replaceAll("：+", "：");    // 合并多个冒号

        // 4) 规范冒号前后空格
        text = text.replaceAll("\\s*：\\s*", "：");

        // 5) 去掉多余冒号
        text = text.replaceAll("：([\\p{Punct}&&[^。！？]])", "$1"); // 去掉多余冒号
        text = text.replaceAll("：\\s*$", "");  // 去掉行尾冒号

        // 6. 确保换行符保留
        // 合并连续换行
        text = text.replaceAll("\n+", "\n");

        // 去掉开头和结尾的空白字符
        text = text.trim();

        return text;
    }


    /** 工具方法：对象转 JSON 字符串 */
    private String toJson(Object obj) {
        return obj == null ? null : JSON.toJSONString(obj);
    }

    // 工具方法：从 Map 中安全获取字符串
    private String getString(Map<String, Object> map, String key, String defaultValue) {
        Object value = map.get(key);
        return value != null ? value.toString() : defaultValue;
    }

    private String getString(Map<String, Object> map, String key) {
        return getString(map, key, null);
    }



    @Override
    public TableDataInfo<PatientRecordWithQCResultDTO> patientRecordList(
        PageQuery pageQuery,
        String recordId,
        String admissionNo,
        String patientName,
        String admissionDept,
        String status,
        String attendingDoctor,
        String qcStartDate,
        String qcEndDate,
        String viewed,
        Long userId
    ) {
        Page<PatientRecord> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());

        LambdaQueryWrapper<PatientRecord> lqw = Wrappers.lambdaQuery(PatientRecord.class)
            .ne(PatientRecord::getStatus, 0);

        // ✅ 添加查询条件
        if (recordId != null && !recordId.isEmpty()) {
            lqw.eq(PatientRecord::getId, recordId);
        }

        // 自定义排序：已质控记录排前面按最后质控时间倒序，未质控记录排后面按创建时间倒序
        lqw.last("ORDER BY status = 2 DESC, CASE WHEN status = 2 THEN (SELECT MAX(qc_end_time) FROM medical_record_result mrr WHERE mrr.patient_record_id = patient_record.id) ELSE create_date END DESC");
        if (admissionNo != null && !admissionNo.isEmpty()) {
            lqw.eq(PatientRecord::getAdmissionNo, admissionNo);
        }
        if (patientName != null && !patientName.isEmpty()) {
            lqw.like(PatientRecord::getName, patientName);
        }
        if (admissionDept != null && !admissionDept.isEmpty()) {
            lqw.like(PatientRecord::getAdmissionDept, admissionDept);
        }
        if (status != null && !status.isEmpty()) {
            lqw.eq(PatientRecord::getStatus, Integer.parseInt(status));
        }
        if (attendingDoctor != null && !attendingDoctor.isEmpty()) {
            lqw.like(PatientRecord::getAttendingDoctor, attendingDoctor);
        }
        // 质控完成时间范围查询（>=开始时间，<=结束时间）
        if ((qcStartDate != null && !qcStartDate.isEmpty()) || (qcEndDate != null && !qcEndDate.isEmpty())) {
            StringBuilder existsSql = new StringBuilder("SELECT 1 FROM medical_record_result mrr WHERE mrr.patient_record_id = patient_record.id");
            if (qcStartDate != null && !qcStartDate.isEmpty()) {
                String startTime = qcStartDate + " 00:00:00";
                existsSql.append(" AND mrr.qc_end_time >= '").append(startTime).append("'");
            }
            if (qcEndDate != null && !qcEndDate.isEmpty()) {
                String endTime = qcEndDate + " 23:59:59";
                existsSql.append(" AND mrr.qc_end_time <= '").append(endTime).append("'");
            }
            lqw.exists(existsSql.toString());
        }

        Set<String> viewedRecordIds = new HashSet<>();
        boolean filterViewed = userId != null && viewed != null && !viewed.isEmpty();
        if (userId != null) {
            List<MedicalRecordView> allViews;
            if (filterViewed) {
                allViews = medicalRecordViewMapper.selectList(
                    Wrappers.<MedicalRecordView>lambdaQuery()
                        .eq(MedicalRecordView::getUserId, userId)
                );
            } else {
                allViews = Collections.emptyList();
            }
            for (MedicalRecordView view : allViews) {
                viewedRecordIds.add(view.getPatientRecordId());
            }
            if (filterViewed) {
                boolean wantViewed = Boolean.parseBoolean(viewed);
                if (wantViewed) {
                    if (viewedRecordIds.isEmpty()) {
                        Page<PatientRecordWithQCResultDTO> emptyPage = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize(), 0);
                        emptyPage.setRecords(Collections.emptyList());
                        return TableDataInfo.build(emptyPage);
                    }
                    lqw.in(PatientRecord::getId, viewedRecordIds);
                } else {
                    if (!viewedRecordIds.isEmpty()) {
                        lqw.notIn(PatientRecord::getId, viewedRecordIds);
                    }
                }
            }
        }

        Page<PatientRecord> resultPage = patientRecordMapper.selectPage(page, lqw);

        List<PatientRecord> records = resultPage.getRecords();
        List<String> recordIds = records.stream().map(PatientRecord::getId).collect(Collectors.toList());

        // 预先统计每个病历的质控问题数量与最新质控结束时间
        final Map<String, Integer> qcIssueCountMap = new HashMap<>();
        final Map<String, LocalDateTime> latestQcEndMap = new HashMap<>();
        if (!records.isEmpty()) {
            List<MedicalRecordResult> qcResults = medicalRecordResultMapper.selectList(
                Wrappers.<MedicalRecordResult>lambdaQuery()
                    .in(MedicalRecordResult::getPatientRecordId, recordIds)
            );
            for (MedicalRecordResult result : qcResults) {
                // 统计质控问题数量（qc_comments JSON 数组长度）
                int issueCount = 0;
                String qcComments = result.getQcComments();
                if (qcComments != null && !qcComments.isEmpty()) {
                    try {
                        List<?> comments = objectMapper.readValue(qcComments, List.class);
                        if (comments != null) {
                            issueCount = comments.size();
                        }
                    } catch (Exception ignored) {
                        // 忽略解析异常，保持默认 0
                    }
                }
                if (issueCount > 0) {
                    qcIssueCountMap.merge(result.getPatientRecordId(), issueCount, Integer::sum);
                }

                if (result.getQcEndTime() == null) {
                    continue;
                }
                latestQcEndMap.merge(result.getPatientRecordId(), result.getQcEndTime(),
                    (existing, incoming) -> incoming.isAfter(existing) ? incoming : existing);
            }
        }

        if (userId != null && !filterViewed && !recordIds.isEmpty()) {
            List<MedicalRecordView> viewRecords = medicalRecordViewMapper.selectList(
                Wrappers.<MedicalRecordView>lambdaQuery()
                    .eq(MedicalRecordView::getUserId, userId)
                    .in(MedicalRecordView::getPatientRecordId, recordIds)
            );
            for (MedicalRecordView view : viewRecords) {
                viewedRecordIds.add(view.getPatientRecordId());
            }
        }

        List<PatientRecordWithQCResultDTO> dtoList = records.stream().map(record -> {
            PatientRecordWithQCResultDTO dto = new PatientRecordWithQCResultDTO();
            dto.setRecordId(record.getId());
            dto.setPatientId(record.getPatientId());
            dto.setAdmissionNo(record.getAdmissionNo());
            dto.setPatientName(record.getName());
            dto.setStatus(record.getStatus());
            dto.setCreateDate(record.getCreateDate());
            // 新增字段
            dto.setGender(record.getGender());
            dto.setAge(record.getAge());
            dto.setAdmissionDate(record.getAdmissionDate());
            dto.setDischargeDate(record.getDischargeDate());
            dto.setAdmissionDept(record.getAdmissionDept());
            dto.setDischargeDept(record.getDischargeDept());
            dto.setAttendingDoctor(record.getAttendingDoctor());
            dto.setNurse(record.getNurse());
            dto.setQcResultCount(qcIssueCountMap.getOrDefault(record.getId(), 0));
            dto.setLatestQcEndTime(latestQcEndMap.get(record.getId()));
            dto.setViewed(viewedRecordIds.contains(record.getId()));
            return dto;
        }).collect(Collectors.toList());

        Page<PatientRecordWithQCResultDTO> dtoPage = new Page<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal());
        dtoPage.setRecords(dtoList);

        return TableDataInfo.build(dtoPage);
    }


    @Override
    public List<RecordDetailItemDTO> getDetailListById(String id) {
        List<Map<String, Object>> mapList = patientRecordMapper.selectDetailMapById(id);
        List<RecordDetailItemDTO> dtoList = new ArrayList<>();

        for (Map<String, Object> map : mapList) {
            String content = (String) map.get("content");
            String typeName = (String) map.get("typeName");

            // 判断 content 是否为空或为 "[]"
            if (content == null || content.isEmpty() || "[]".equals(content)) {
                continue;  // 跳过该记录
            }

            // 创建 RecordDetailItemDTO 对象，并填充数据
            RecordDetailItemDTO dto = new RecordDetailItemDTO();
            dto.setType(map.get("type") != null ? ((Number) map.get("type")).longValue() : null);
            dto.setTypeName(typeName);

            // 根据 typeName 判断是否需要拆分 content 或格式化
            String formattedContent = formatContentByType(content, typeName);
            dto.setContent(formattedContent);  // 设置格式化后的内容

            // 处理 qcComments
            String qcCommentsStr = (String) map.get("qcComments");
            List<Map<String, Object>> qcCommentsList = processQcComments(qcCommentsStr);
            dto.setQcCommentsList(qcCommentsList);

            // 处理其他字段
            dto.setQcResult(map.get("qcResult") != null ? ((Number) map.get("qcResult")).intValue() : null);
            dto.setQcScore((String) map.get("qcScore"));
            dto.setQcName((String) map.get("qcName"));
            dto.setQcReviewComments((String) map.get("qcReviewComments"));
            dto.setQcStartTime(map.get("qcStartTime") instanceof LocalDateTime ? (LocalDateTime) map.get("qcStartTime") : null);
            dto.setQcEndTime(map.get("qcEndTime") instanceof LocalDateTime ? (LocalDateTime) map.get("qcEndTime") : null);

            // 将 dto 添加到结果列表中
            dtoList.add(dto);
        }

        return dtoList;
    }

    private String formatContentByType(String content, String typeName) {
        StringBuilder formattedContent = new StringBuilder();

        switch (typeName) {
            case "病程记录":
                formattedContent.append(formatMedicalRecords(content, true));
                break;
            case "阶段小结":
            case "查房记录":
            case "会诊记录":
            case "疑难病例讨论记录":
            case "超长住院讨论记录":
            case "死亡病例讨论记录":
            case "抢救记录":
            case "手术记录":
            case "医嘱记录":
                // 医嘱记录需要按类型排序：先长期医嘱，后临时医嘱
                formattedContent.append(formatOrdersWithTypeSort(content));
                break;

            case "知情同意书":
                // 知情同意书带分割线格式化
                formattedContent.append(formatConsentFormsContent(content));
                break;

            case "检验报告单":
            case "检查报告单":
                // 检验 / 检查报告单单独格式化
                formattedContent.append(formatLabReportContent(content));
                break;

            default:
                // 其他类型直接返回
                formattedContent.append(content);
                break;
        }

        return formattedContent.toString();
    }

    /**
     * 通用数组类的处理（病程记录、医嘱等）
     */
    private String formatMedicalRecords(String content) {
        return formatMedicalRecords(content, false);
    }

    private String formatMedicalRecords(String content, boolean sortByTimeDesc) {
        StringBuilder formattedContent = new StringBuilder();

        try {
            List<String> records = objectMapper.readValue(content, List.class);
            if (records == null || records.isEmpty()) {
                return "";
            }

            List<String> processedRecords = records.stream()
                .filter(record -> record != null && !record.trim().isEmpty())
                .collect(Collectors.toList());

            if (sortByTimeDesc && processedRecords.size() > 1) {
                processedRecords.sort((r1, r2) -> {
                    LocalDateTime dt1 = extractRecordDateTime(r1);
                    LocalDateTime dt2 = extractRecordDateTime(r2);
                    if (dt1 == null && dt2 == null) {
                        return 0;
                    }
                    if (dt1 == null) {
                        return 1;
                    }
                    if (dt2 == null) {
                        return -1;
                    }
                    return dt1.compareTo(dt2);
                });
            }

            for (String record : processedRecords) {
                formattedContent.append(record.trim()).append("\n\n");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return "解析记录失败";
        }

        return formattedContent.toString().trim();
    }

    /**
     * 医嘱记录格式化并排序：先长期医嘱，后临时医嘱
     */
    private String formatOrdersWithTypeSort(String content) {
        StringBuilder formattedContent = new StringBuilder();

        try {
            List<String> records = objectMapper.readValue(content, List.class);
            if (records == null || records.isEmpty()) {
                return "";
            }

            List<String> processedRecords = records.stream()
                .filter(record -> record != null && !record.trim().isEmpty())
                .collect(Collectors.toList());

            // 按医嘱类型排序：长期医嘱在前，临时医嘱在后
            if (processedRecords.size() > 1) {
                processedRecords.sort((r1, r2) -> {
                    String type1 = extractOrderType(r1);
                    String type2 = extractOrderType(r2);

                    // 长期医嘱优先级为0，临时医嘱优先级为1
                    int priority1 = "长期医嘱".equals(type1) ? 0 : 1;
                    int priority2 = "长期医嘱".equals(type2) ? 0 : 1;

                    // 先按类型排序（长期在前）
                    int typeCompare = Integer.compare(priority1, priority2);
                    if (typeCompare != 0) {
                        return typeCompare;
                    }

                    // 同类型内保持原有顺序（或可以按时间排序）
                    return 0;
                });
            }

            for (String record : processedRecords) {
                formattedContent.append(record.trim()).append("\n\n");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return "解析记录失败";
        }

        return formattedContent.toString().trim();
    }

    /**
     * 从医嘱格式化字符串中提取类型（类型：xxx）
     * 格式示例：xxx（类型：临时医嘱，状态：...）
     */
    private String extractOrderType(String orderStr) {
        if (orderStr == null || orderStr.isEmpty()) {
            return "";
        }
        // 匹配 "类型：xxx，"
        Pattern pattern = Pattern.compile("类型：([^，]+)");
        Matcher matcher = pattern.matcher(orderStr);
        if (matcher.find()) {
            return matcher.group(1).trim();
        }
        return "";
    }

    private LocalDateTime extractRecordDateTime(String record) {
        if (record == null) {
            return null;
        }
        Matcher matcher = RECORD_DATETIME_PREFIX.matcher(record.trim());
        if (matcher.find()) {
            String dateTimeStr = matcher.group(1).replace('T', ' ');
            return parseDateTime(dateTimeStr);
        }
        return null;
    }

    /**
     * 知情同意书的专用格式化（带分割线）
     */
    private String formatConsentFormsContent(String content) {
        if (content == null || content.trim().isEmpty()) {
            return "";
        }

        StringBuilder formattedContent = new StringBuilder();

        try {
            // 解析JSON数组，每个元素为一份知情同意书
            List<String> consentForms = objectMapper.readValue(content, List.class);

            for (String form : consentForms) {
                if (form == null || form.trim().isEmpty()) {
                    continue;
                }

                // 直接添加内容和分割线
                formattedContent.append(form.trim())
                    .append("\n\n========================================================== 分隔线 ==========================================================\n\n");
            }

        } catch (Exception e) {
            e.printStackTrace();
            return "解析知情同意书失败";
        }

        return formattedContent.toString().trim();
    }

    /**
     * 检验/检查报告单的专用格式化
     */
    public String formatLabReportContent(String content) {
        if (content == null || content.trim().isEmpty()) {
            return "";
        }

        StringBuilder formattedContent = new StringBuilder();

        try {
            // 解析JSON数组，每个元素为一份报告
            List<String> reports = objectMapper.readValue(content, List.class);

            for (String report : reports) {
                if (report == null || report.trim().isEmpty()) {
                    continue;
                }

                String text = report;

                // 1. 统一长横线分隔
                text = text.replaceAll("-{5,}", "\n-------------------------------------------------------------------------------------------------\n")
                    .replaceAll("检验结果[-]+", "\n检验结果：\n")
                    .replaceAll("◆", "\n◆");

                // 2. 病人信息整合到一行，确保格式一致
                text = text.replaceAll("(病人姓名|性别|年龄|科室|门诊号|住院号|床号)([^\\n]+)", "$1：$2");

                // 3. 处理检验项目和检验结果格式
                text = text.replaceAll("检验项目", "\n检验项目")
                    .replaceAll("检验结果", "检验结果");

                // 4. 保持原始的 "检验项目 检验结果 单位 结果标志 结果参考" 行不变，统一格式
                text = text.replaceAll("(检验项目|检验结果|单位|结果标志|结果参考)", "$1");

                // 5. 处理特殊简短报告（如乙肝、梅毒等）
                if (text.contains("检验结果：") && (text.contains("HBsAg") || text.contains("抗-HBs") || text.contains("梅毒螺旋体抗体"))) {
                    text = text.replaceAll("检验结果：", "\n检验结果：\n");
                }

                text = text.replaceAll("结果参考", "结果参考 ");

                // >>>>>>>> 新增：自动在每个检验项目前换行 <<<<<<<<
                text = text.replaceAll("(◆?)([\\u4e00-\\u9fa5]+\\([^)]+\\))", "\n$1$2"); // 特别处理包含-的项

                // 修复：◆开头的行，如果下一行以中文开头，且上一行以字母/数字结尾，则合并
                text = text.replaceAll("(◆[\\S&&[^◆]]*)\n([\\u4e00-\\u9fa5])", "$1$2");


                // 6. 统一处理检验项目格式，保持一致
                text = text.replaceAll("(◆[^\n]+)([\\d\\.]+)", "$1   $2");

                // 7. 去除多余的空格和空行
                StringBuilder sb = new StringBuilder();
                String[] lines = text.split("\n");
                for (String line : lines) {
                    if (!line.trim().isEmpty()) {
                        sb.append(line.trim()).append("\n");
                    }
                }

                // 拼接报告，并确保报告之间有空行分隔
                formattedContent.append(sb.toString().trim())
                    .append("\n\n========================================================== 分隔线 ==========================================================\n\n");
            }

        } catch (Exception e) {
            e.printStackTrace();
            return "解析检验报告失败";
        }

        return formattedContent.toString().trim();
    }


    private List<RecordDetailItemDTO> convertToDtoList(List<Map<String, Object>> mapList) {
        List<RecordDetailItemDTO> dtoList = new ArrayList<>();

        for (Map<String, Object> map : mapList) {
            RecordDetailItemDTO dto = new RecordDetailItemDTO();

            dto.setType((Long) map.get("type"));
            dto.setTypeName((String) map.get("typeName"));
            dto.setContent((String) map.get("content"));

            Object qcResultObj = map.get("qcResult");
            dto.setQcResult(qcResultObj != null ? ((Number) qcResultObj).intValue() : null);

            dto.setQcScore((String) map.get("qcScore"));
            dto.setQcComments((String) map.get("qcComments"));
            dto.setQcName((String) map.get("qcName"));

            Object startTime = map.get("qcStartTime");
            if (startTime instanceof LocalDateTime) {
                dto.setQcStartTime((LocalDateTime) startTime);
            }

            Object endTime = map.get("qcEndTime");
            if (endTime instanceof LocalDateTime) {
                dto.setQcEndTime((LocalDateTime) endTime);
            }

            dtoList.add(dto);
        }

        return dtoList;
    }



    /**
     * 保存质控意见和签名
     */
    public boolean saveQcOpinion(String patientRecordId, String qcReviewComments, String qcName, String qcType) {
        Map<String, Object> record = medicalRecordResultMapper.selectByPatientRecordIdAndType(patientRecordId, qcType);
        if (record == null) {
            return false;
        }

        // 直接更新，不管原来有没有意见
        int rows = medicalRecordResultMapper.updateQcReviewByPatientRecordIdAndType(patientRecordId, qcType, qcReviewComments, qcName);
        return rows > 0;
    }


    private LocalDateTime parseDateTime(String dateStr) {
        if (dateStr == null || dateStr.trim().isEmpty()) {
            return null;
        }
        try {
            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            return LocalDateTime.parse(dateStr, dtf);
        } catch (Exception e1) {
            try {
                DateTimeFormatter dtfNoSeconds = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
                return LocalDateTime.parse(dateStr, dtfNoSeconds);
            } catch (Exception e2) {
                try {
                    DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                    LocalDate date = LocalDate.parse(dateStr, df);
                    return LocalDateTime.of(date, LocalTime.MIDNIGHT);
                } catch (Exception e3) {
                    return null;
                }
            }
        }
    }

    // 处理 qcComments 字段
    private List<Map<String, Object>> processQcComments(String qcCommentsStr) {
        List<Map<String, Object>> qcCommentsList = new ArrayList<>();

        if (qcCommentsStr == null || qcCommentsStr.trim().isEmpty()) {
            return qcCommentsList;
        }

        try {
            // 多步骤清理
            String cleanedJson = qcCommentsStr.trim();

            // 步骤1: 移除Markdown代码块
            cleanedJson = removeMarkdownWrapper(cleanedJson);

            // 步骤2: 移除其他可能的非法字符
            cleanedJson = removeIllegalCharacters(cleanedJson);



            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

            List<Map<String, Object>> comments = objectMapper.readValue(cleanedJson,
                new TypeReference<List<Map<String, Object>>>() {});

            for (Map<String, Object> comment : comments) {
                if ("fail".equals(comment.get("result"))) {
                    qcCommentsList.add(comment);
                }
            }

        } catch (Exception e) {
            System.err.println("处理qc_comments失败: " + e.getMessage());
            System.err.println("请检查数据库中的qc_comments字段内容，应该是纯JSON格式");
            e.printStackTrace();
        }

        return qcCommentsList;
    }

    private String removeMarkdownWrapper(String str) {
        if (str == null) return null;

        String cleaned = str.trim();

        // 移除各种Markdown代码块格式
        cleaned = cleaned.replaceAll("^```(json|JSON)?\\s*", "");
        cleaned = cleaned.replaceAll("\\s*```$", "");
        cleaned = cleaned.replaceAll("^``(json|JSON)?\\s*", "");
        cleaned = cleaned.replaceAll("\\s*``$", "");

        return cleaned.trim();
    }

    private String removeIllegalCharacters(String str) {
        if (str == null) return null;

        // 移除BOM字符和其他控制字符
        return str.replace("\uFEFF", "")
            .replaceAll("^[\\p{C}]+", "")
            .replaceAll("[\\p{C}]+$", "")
            .trim();
    }




    @Override
    public boolean isRecordViewedByUser(String patientRecordId, Long userId) {
        if (patientRecordId == null || userId == null) {
            return false;
        }
        return medicalRecordViewMapper.exists(
            Wrappers.lambdaQuery(MedicalRecordView.class)
                .eq(MedicalRecordView::getPatientRecordId, patientRecordId)
                .eq(MedicalRecordView::getUserId, userId)
        );
    }

    @Override
    public boolean markRecordAsViewed(String patientRecordId, Long userId) {
        if (patientRecordId == null || userId == null) {
            return false;
        }
        if (isRecordViewedByUser(patientRecordId, userId)) {
            return true;
        }
        MedicalRecordView view = new MedicalRecordView();
        view.setPatientRecordId(patientRecordId);
        view.setUserId(userId);
        view.setViewTime(LocalDateTime.now());
        return medicalRecordViewMapper.insert(view) > 0;
    }

    @Override
    public boolean cancelRecordViewed(String patientRecordId, Long userId) {
        if (patientRecordId == null || userId == null) {
            return false;
        }
        return medicalRecordViewMapper.delete(
            Wrappers.lambdaQuery(MedicalRecordView.class)
                .eq(MedicalRecordView::getPatientRecordId, patientRecordId)
                .eq(MedicalRecordView::getUserId, userId)
        ) > 0;
    }

}
