package com.zksy.base.warning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zksy.base.warning.domain.*;
import com.zksy.base.warning.mapper.*;
import com.zksy.base.warning.service.EarlyWarningService;
import com.zksy.common.core.domain.entity.SysDictData;
import com.zksy.common.utils.DictUtils;
import com.zksy.service.MinioFileStorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
public class EarlyWarningServiceImpl extends ServiceImpl<EarlyWarningMapper, EarlyWarning>
        implements EarlyWarningService {

    @Autowired
    private EarlyWarningMapper earlyWarningMapper;
    @Autowired
    private AlarmWarningRelMapper alarmWarningRelMapper;
    @Autowired
    private WarningAttachmentMapper warningAttachmentMapper;
    @Autowired
    private WarningDisposalMapper warningDisposalMapper;
    @Autowired
    private WarningTodoMapper warningTodoMapper;

    @Autowired
    private WarningArchiveMapper warningArchiveMapper;
    @Autowired
    private MinioFileStorageService minioFileStorageService;

    @Override
    public IPage<Map<String, Object>> getWarningList(Page<?> page, String warningName, String warningType, String warningLevel, String status) {
        return earlyWarningMapper.selectWarningList(page, warningName, warningType, warningLevel, status);
    }

    @Override
    public IPage<Map<String, Object>> searchWarnings(Page<?> page, String warningName, String warningNo, String warningType, String warningLevel, String status, String location, String publisher, String ownershipUnit, LocalDateTime startTime, LocalDateTime endTime) {
        return earlyWarningMapper.searchWarnings(page, warningName, warningNo, warningType, warningLevel, status, location, publisher, ownershipUnit, startTime, endTime);
    }

    @Override
    public IPage<Map<String, Object>> getTodoList(Page<?> page, String userName, String todoType, String warningName) {
        return earlyWarningMapper.selectTodoList(page, userName, todoType, warningName);
    }

    @Override
    public Map<String, Object> getWarningDetail(String warningId) {
        Map<String, Object> detail = earlyWarningMapper.selectWarningDetail(warningId);
        if (detail != null) {
            detail.put("attachmentList", getAttachmentList(warningId));
            detail.put("disposalList", getDisposalList(warningId));
            detail.put("alarmList", getLinkedAlarms(warningId));
        }
        return detail;
    }

    @Override
    public Map<String, Object> getWarningFullDetail(String warningId) {
        Map<String, Object> result = new HashMap<>();
        Map<String, Object> basicInfo = earlyWarningMapper.selectWarningDetail(warningId);
        if (basicInfo == null) {
            return null;
        }

        result.put("basicInfo", basicInfo);
        result.put("gisLocation", getGisLocation(basicInfo));
        result.put("disposalHistory", getDisposalHistory(warningId));
        result.put("attachmentList", getAttachmentList(warningId));
        result.put("alarmList", getLinkedAlarms(warningId));
        result.put("electronicArchive", generateElectronicArchive(basicInfo));

        return result;
    }

    private Map<String, Object> getGisLocation(Map<String, Object> warningInfo) {
        Map<String, Object> gis = new HashMap<>();
        gis.put("longitude", warningInfo.get("longitude"));
        gis.put("latitude", warningInfo.get("latitude"));
        gis.put("location", warningInfo.get("location"));
        return gis;
    }

    private Map<String, Object> generateElectronicArchive(Map<String, Object> warningInfo) {
        String warningId = (String) warningInfo.get("warning_id");
        
        // 先查询是否已存在归档记录
        LambdaQueryWrapper<WarningArchive> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(WarningArchive::getWarningId, warningId);
        WarningArchive existingArchive = warningArchiveMapper.selectOne(wrapper);
        
        if (existingArchive != null) {
            // 如果已存在，直接返回
            Map<String, Object> archive = new HashMap<>();
            archive.put("archiveId", existingArchive.getArchiveId());
            archive.put("archiveNo", existingArchive.getArchiveNo());
            archive.put("createTime", existingArchive.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            archive.put("archiveContent", existingArchive.getArchiveContent());
            archive.put("archiveStatus", existingArchive.getArchiveStatus());
            return archive;
        }
        
        // 如果不存在，创建新归档
        WarningArchive archive = new WarningArchive();
        archive.setWarningId(warningId);
        archive.setArchiveNo("EA_" + warningInfo.get("warning_no"));
        archive.setWarningNo((String) warningInfo.get("warning_no"));
        archive.setWarningName((String) warningInfo.get("warning_name"));
        archive.setWarningType((String) warningInfo.get("warning_type"));
        archive.setWarningLevel((String) warningInfo.get("warning_level"));
        archive.setLocation((String) warningInfo.get("location"));
        archive.setLongitude(warningInfo.get("longitude") != null ? ((Number) warningInfo.get("longitude")).doubleValue() : null);
        archive.setLatitude(warningInfo.get("latitude") != null ? ((Number) warningInfo.get("latitude")).doubleValue() : null);
        archive.setOwnershipUnit((String) warningInfo.get("ownership_unit"));
        archive.setPublisher((String) warningInfo.get("publisher"));
        archive.setPublishTime(warningInfo.get("publish_time") instanceof LocalDateTime ? (LocalDateTime) warningInfo.get("publishTime") : null);
        archive.setHandler((String) warningInfo.get("handler"));
        archive.setWarningContent((String) warningInfo.get("warning_content"));
        archive.setArchiveContent((String) warningInfo.get("warning_content"));
        archive.setArchiveStatus("已归档");
        archive.setCreateTime(LocalDateTime.now());
        
        warningArchiveMapper.insert(archive);
        
        Map<String, Object> result = new HashMap<>();
        result.put("archiveId", archive.getArchiveId());
        result.put("archiveNo", archive.getArchiveNo());
        result.put("createTime", archive.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        result.put("archiveContent", archive.getArchiveContent());
        result.put("archiveStatus", archive.getArchiveStatus());
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveWarning(EarlyWarning warning, List<String> alarmIds, List<MultipartFile> files) {
        String warningNo = "WJ" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        warning.setWarningNo(warningNo);
        warning.setStatus("DRAFT");
        warning.setCreateTime(LocalDateTime.now());
        warning.setUpdateTime(LocalDateTime.now());

        boolean result = save(warning);
        if (result) {
            if (alarmIds != null && !alarmIds.isEmpty()) {
                linkAlarms(warning.getWarningId(), alarmIds);
            }
            if (files != null && !files.isEmpty()) {
                saveAttachments(warning.getWarningId(), files);
            }
        }
        return result;
    }

    /**
     * 保存附件
     */
    private void saveAttachments(String warningId, List<MultipartFile> files) {
        try {
            for (MultipartFile file : files) {
                String path = minioFileStorageService.uploadFile(file, "warning");
                // 上传文件
                String fileName = path.substring(path.lastIndexOf("/") + 1);
                // 保存附件信息
                WarningAttachment attachment = new WarningAttachment();
                attachment.setWarningId(warningId);
                attachment.setAttachmentName(fileName);
                attachment.setAttachmentUrl(path);
                // 部分 MIME（如 vnd.openxmlformats-officedocument.*）长度超过 64，写入前按 DB 列宽截断兜底
                attachment.setAttachmentType(truncateAttachmentType(file.getContentType()));
                attachment.setAttachmentSize(file.getSize());
                attachment.setCreateTime(LocalDateTime.now());
                warningAttachmentMapper.insert(attachment);
            }
        } catch (Exception e) {
            throw new RuntimeException("附件保存失败", e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateWarning(EarlyWarning warning, List<String> alarmIds, List<MultipartFile> files) {
        warning.setUpdateTime(LocalDateTime.now());
        boolean result = updateById(warning);
        if (result) {
            if (alarmIds != null) {
                linkAlarms(warning.getWarningId(), alarmIds);
            }
            if (files != null && !files.isEmpty()) {
                saveAttachments(warning.getWarningId(), files);
            }
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteWarning(String warningId) {
        // 先查询附件列表，删除物理文件
        List<WarningAttachment> attachments = warningAttachmentMapper.selectList(
                new LambdaQueryWrapper<WarningAttachment>()
                        .eq(WarningAttachment::getWarningId, warningId)
        );
        for (WarningAttachment attachment : attachments) {
            String attachmentUrl = attachment.getAttachmentUrl();
            if (attachmentUrl != null && !attachmentUrl.isEmpty()) {
                // 删除minio文件
                minioFileStorageService.deleteFile(attachmentUrl);
            }
        }

        // 删除关联数据
        LambdaQueryWrapper<AlarmWarningRel> relWrapper = new LambdaQueryWrapper<>();
        relWrapper.eq(AlarmWarningRel::getWarningId, warningId);
        alarmWarningRelMapper.delete(relWrapper);

        LambdaQueryWrapper<WarningAttachment> attachmentWrapper = new LambdaQueryWrapper<>();
        attachmentWrapper.eq(WarningAttachment::getWarningId, warningId);
        warningAttachmentMapper.delete(attachmentWrapper);

        LambdaQueryWrapper<WarningDisposal> disposalWrapper = new LambdaQueryWrapper<>();
        disposalWrapper.eq(WarningDisposal::getWarningId, warningId);
        warningDisposalMapper.delete(disposalWrapper);

        LambdaQueryWrapper<WarningTodo> todoWrapper = new LambdaQueryWrapper<>();
        todoWrapper.eq(WarningTodo::getWarningId, warningId);
        warningTodoMapper.delete(todoWrapper);

        LambdaQueryWrapper<WarningArchive> archiveWrapper = new LambdaQueryWrapper<>();
        archiveWrapper.eq(WarningArchive::getWarningId, warningId);
        warningArchiveMapper.delete(archiveWrapper);

        // 删除主表记录
        return removeById(warningId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteBatchWarning(List<String> warningIds) {
        for (String warningId : warningIds) {
            deleteWarning(warningId);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean publishWarning(String warningId) {
        EarlyWarning warning = getById(warningId);
        if (warning == null) return false;

        warning.setStatus("PENDING");
        warning.setPublishTime(LocalDateTime.now());
        warning.setUpdateTime(LocalDateTime.now());

        boolean result = updateById(warning);

        if (result) {
            addDisposalRecord(warningId, "RELEASE", null, null, warning.getHandler(), "系统发布预警信息");
            createTodo(warningId, warning.getHandler(), "待办预警", "TODO");
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean upgradeWarning(String warningId, String newLevel, String disposalContent) {
        EarlyWarning warning = getById(warningId);
        if (warning == null) return false;

        String oldLevel = warning.getWarningLevel();
        warning.setWarningLevel(newLevel);
        warning.setUpdateTime(LocalDateTime.now());

        boolean result = updateById(warning);
        if (result) {
            addDisposalRecord(warningId, "UPGRADE", oldLevel, newLevel, warning.getHandler(), disposalContent);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean resolveWarning(String warningId, String disposalContent) {
        EarlyWarning warning = getById(warningId);
        if (warning == null) return false;

        warning.setStatus("CLOSED");
        warning.setUpdateTime(LocalDateTime.now());

        boolean result = updateById(warning);
        if (result) {
            addDisposalRecord(warningId, "RESOLVE", null, null, warning.getHandler(), disposalContent);
            completeTodo(warningId);
            
            // 解除预警时自动创建归档
            Map<String, Object> warningDetail = earlyWarningMapper.selectWarningDetail(warningId);
            if (warningDetail != null) {
                generateElectronicArchive(warningDetail);
            }
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean returnWarning(String warningId, String disposalContent) {
        EarlyWarning warning = getById(warningId);
        if (warning == null) return false;

        warning.setStatus("DRAFT");
        warning.setUpdateTime(LocalDateTime.now());

        boolean result = updateById(warning);
        if (result) {
            addDisposalRecord(warningId, "RETURN", null, null, warning.getHandler(), disposalContent);
            // 退回后删除待办记录，因为直接回到草稿状态
            LambdaQueryWrapper<WarningTodo> todoWrapper = new LambdaQueryWrapper<>();
            todoWrapper.eq(WarningTodo::getWarningId, warningId);
            warningTodoMapper.delete(todoWrapper);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean supervisionWarning(String warningId, String supervisionUser, String supervisionContent, String notificationType, String notificationContent, String attachmentUrl) {
        WarningDisposal disposal = new WarningDisposal();
        disposal.setWarningId(warningId);
        disposal.setDisposalType("SUPERVISION");
        disposal.setDisposalUser(supervisionUser);
        disposal.setDisposalContent(supervisionContent);
        disposal.setSupervisionUser(supervisionUser);
        disposal.setSupervisionContent(supervisionContent);
        disposal.setNotificationType(notificationType);
        disposal.setCreateTime(LocalDateTime.now());

        return warningDisposalMapper.insert(disposal) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addLeaderInstruction(String warningId, String leaderName, String instructionContent, String smsReceivers) {
        WarningDisposal disposal = new WarningDisposal();
        disposal.setWarningId(warningId);
        disposal.setDisposalType("INSTRUCTION");
        disposal.setDisposalUser(leaderName);
        disposal.setDisposalContent(instructionContent);
        disposal.setCreateTime(LocalDateTime.now());

        return warningDisposalMapper.insert(disposal) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean linkAlarms(String warningId, List<String> alarmIds) {
        LambdaQueryWrapper<AlarmWarningRel> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AlarmWarningRel::getWarningId, warningId);
        alarmWarningRelMapper.delete(wrapper);

        if (alarmIds != null && !alarmIds.isEmpty()) {
            for (String alarmId : alarmIds) {
                AlarmWarningRel rel = new AlarmWarningRel();
                rel.setWarningId(warningId);
                rel.setAlarmId(alarmId);
                rel.setCreateTime(LocalDateTime.now());
                alarmWarningRelMapper.insert(rel);
            }
        }
        return true;
    }

    @Override
    public List<Map<String, Object>> getLinkedAlarms(String warningId) {
        return alarmWarningRelMapper.selectAlarmListByWarningId(warningId);
    }

    @Override
    public List<Map<String, Object>> getDisposalList(String warningId) {
        return warningDisposalMapper.selectDisposalList(warningId);
    }

    @Override
    public List<Map<String, Object>> getDisposalHistory(String warningId) {
        return warningDisposalMapper.selectDisposalList(warningId);
    }

    @Override
    public IPage<Map<String, Object>> getProcessingWarnings(Page<?> page, String warningType, String warningLevel) {
        return earlyWarningMapper.selectProcessingWarnings(page, warningType, warningLevel);
    }

    @Override
    public IPage<Map<String, Object>> getCompletedWarnings(Page<?> page, String warningType, String warningLevel, LocalDateTime startTime, LocalDateTime endTime) {
        return earlyWarningMapper.selectCompletedWarnings(page, warningType, warningLevel, startTime, endTime);
    }

    @Override
    public List<Map<String, Object>> getAttachments(String warningId) {
        return getAttachmentList(warningId);
    }

    @Override
    public Map<String, Object> getStatistics() {
        List<Map<String, Object>> statsList = earlyWarningMapper.selectStatistics();
        if (statsList != null && !statsList.isEmpty()) {
            return statsList.get(0);
        }
        return new HashMap<>();
    }

    @Override
    public Map<String, Object> getDashboardStatistics() {
        Map<String, Object> result = new HashMap<>();
        
        Map<String, Object> basicStats = getStatistics();
        result.put("basicStats", basicStats);
        
        List<Map<String, Object>> typeStats = getWarningTypeStatistics();
        result.put("typeStats", typeStats);
        
        List<Map<String, Object>> levelStats = getWarningLevelStatistics();
        result.put("levelStats", levelStats);
        
        List<Map<String, Object>> trendStats = getWarningTrendStatistics();
        result.put("trendStats", trendStats);
        
        return result;
    }

    private List<Map<String, Object>> getWarningTypeStatistics() {
        List<SysDictData> types = DictUtils.getDictCache("warning_type");
        List<Map<String, Object>> result = new ArrayList<>();
        if (types != null) {
            for (SysDictData type : types) {
                LambdaQueryWrapper<EarlyWarning> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(EarlyWarning::getWarningType, type.getDictValue());
                long count = count(wrapper);
                
                Map<String, Object> item = new HashMap<>();
                item.put("typeCode", type.getDictValue());
                item.put("typeName", type.getDictLabel());
                item.put("count", count);
                result.add(item);
            }
        }
        return result;
    }

    private List<Map<String, Object>> getWarningLevelStatistics() {
        List<Map<String, Object>> result = new ArrayList<>();
        // 预警级别：1-4
        for (int i = 1; i <= 4; i++) {
            String levelCode = String.valueOf(i);
            LambdaQueryWrapper<EarlyWarning> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(EarlyWarning::getWarningLevel, levelCode);
            long count = count(wrapper);
            
            Map<String, Object> item = new HashMap<>();
            item.put("levelCode", levelCode);
            item.put("count", count);
            result.add(item);
        }
        return result;
    }

    private List<Map<String, Object>> getWarningTrendStatistics() {
        List<Map<String, Object>> result = new ArrayList<>();
        for (int i = 6; i >= 0; i--) {
            LocalDateTime date = LocalDateTime.now().minusDays(i);
            LocalDateTime startOfDay = date.toLocalDate().atStartOfDay();
            LocalDateTime endOfDay = date.toLocalDate().atTime(23, 59, 59);
            
            LambdaQueryWrapper<EarlyWarning> wrapper = new LambdaQueryWrapper<>();
            wrapper.ge(EarlyWarning::getCreateTime, startOfDay);
            wrapper.le(EarlyWarning::getCreateTime, endOfDay);
            long count = count(wrapper);
            
            Map<String, Object> item = new HashMap<>();
            item.put("date", date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            item.put("count", count);
            result.add(item);
        }
        return result;
    }

    @Override
    public List<Map<String, Object>> getTypeConfigList() {
        List<SysDictData> list = DictUtils.getDictCache("warning_type");
        List<Map<String, Object>> result = new ArrayList<>();
        if (list != null) {
            for (SysDictData config : list) {
                Map<String, Object> map = new HashMap<>();
                map.put("dictCode", config.getDictCode());
                map.put("typeCode", config.getDictValue());
                map.put("typeName", config.getDictLabel());
                result.add(map);
            }
        }
        return result;
    }

    private void addDisposalRecord(String warningId, String disposalType, String oldLevel, String newLevel, String disposalUser, String content) {
        WarningDisposal disposal = new WarningDisposal();
        disposal.setWarningId(warningId);
        disposal.setDisposalType(disposalType);
        disposal.setOldLevel(oldLevel);
        disposal.setNewLevel(newLevel);
        disposal.setDisposalUser(disposalUser);
        disposal.setDisposalContent(content);
        disposal.setCreateTime(LocalDateTime.now());
        warningDisposalMapper.insert(disposal);
    }

    private List<Map<String, Object>> getAttachmentList(String warningId) {
        List<WarningAttachment> list = warningAttachmentMapper.selectList(
                new LambdaQueryWrapper<WarningAttachment>()
                        .eq(WarningAttachment::getWarningId, warningId)
                        .orderByDesc(WarningAttachment::getCreateTime)
        );

        List<Map<String, Object>> result = new ArrayList<>();
        for (WarningAttachment attachment : list) {
            Map<String, Object> map = new HashMap<>();
            map.put("attachmentId", attachment.getAttachmentId());
            map.put("attachmentName", attachment.getAttachmentName());
            map.put("attachmentUrl", attachment.getAttachmentUrl());
            map.put("attachmentType", attachment.getAttachmentType());
            map.put("attachmentSize", attachment.getAttachmentSize());
            map.put("createTime", attachment.getCreateTime());
            result.add(map);
        }
        return result;
    }

    private void createTodo(String warningId, String userId, String taskName, String todoType) {
        WarningTodo todo = new WarningTodo();
        todo.setWarningId(warningId);
        todo.setUserId(userId);
        todo.setUserName(userId);
        todo.setTodoType(todoType);
        todo.setReadStatus("UNREAD");
        todo.setTaskName(taskName);
        todo.setCreateTime(LocalDateTime.now());
        warningTodoMapper.insert(todo);
    }

    private void completeTodo(String warningId) {
        LambdaQueryWrapper<WarningTodo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(WarningTodo::getWarningId, warningId)
                .eq(WarningTodo::getTodoType, "TODO");
        List<WarningTodo> todos = warningTodoMapper.selectList(wrapper);

        for (WarningTodo todo : todos) {
            todo.setTodoType("DONE");
            todo.setReadStatus("READ");
            todo.setCompleteTime(LocalDateTime.now());
            warningTodoMapper.updateById(todo);
        }
    }

    @Override
    public WarningArchive getArchiveByWarningId(String warningId) {
        LambdaQueryWrapper<WarningArchive> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(WarningArchive::getWarningId, warningId);
        return warningArchiveMapper.selectOne(wrapper);
    }

    @Override
    public IPage<WarningArchive> getArchiveList(Page<WarningArchive> page, String warningName, String warningType, String warningLevel, LocalDateTime startTime, LocalDateTime endTime) {
        LambdaQueryWrapper<WarningArchive> wrapper = new LambdaQueryWrapper<>();
        
        if (warningName != null && !warningName.isEmpty()) {
            wrapper.like(WarningArchive::getWarningName, warningName);
        }
        if (warningType != null && !warningType.isEmpty()) {
            wrapper.eq(WarningArchive::getWarningType, warningType);
        }
        if (warningLevel != null && !warningLevel.isEmpty()) {
            wrapper.eq(WarningArchive::getWarningLevel, warningLevel);
        }
        if (startTime != null) {
            wrapper.ge(WarningArchive::getCreateTime, startTime);
        }
        if (endTime != null) {
            wrapper.le(WarningArchive::getCreateTime, endTime);
        }
        
        wrapper.orderByDesc(WarningArchive::getCreateTime);
        return warningArchiveMapper.selectPage(page, wrapper);
    }

    private static final Map<String, String> DISPOSAL_TYPE_MAP = new HashMap<>();
    static {
        DISPOSAL_TYPE_MAP.put("RELEASE", "发布预警");
        DISPOSAL_TYPE_MAP.put("UPGRADE", "升级预警");
        DISPOSAL_TYPE_MAP.put("RESOLVE", "解除预警");
        DISPOSAL_TYPE_MAP.put("RETURN", "退回重办");
        DISPOSAL_TYPE_MAP.put("SUPERVISION", "预警督办");
        DISPOSAL_TYPE_MAP.put("INSTRUCTION", "领导批示");
    }

    @Override
    public List<WarningDisposal> getDisposalProcess(String warningId) {
        LambdaQueryWrapper<WarningDisposal> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(WarningDisposal::getWarningId, warningId);
        wrapper.orderByAsc(WarningDisposal::getCreateTime);
        return warningDisposalMapper.selectList(wrapper);
    }

    @Override
    public Map<String, Object> getProcessDiagram(String warningId) {
        Map<String, Object> result = new HashMap<>();
        List<Map<String, Object>> nodes = new ArrayList<>();
        List<Map<String, Object>> edges = new ArrayList<>();

        EarlyWarning warning = earlyWarningMapper.selectById(warningId);
        if (warning == null) {
            result.put("error", "预警不存在");
            return result;
        }

        List<WarningDisposal> disposals = getDisposalProcess(warningId);

        Map<String, Object> startNode = new HashMap<>();
        startNode.put("id", "start");
        startNode.put("name", "预警创建");
        startNode.put("type", "startEvent");
        startNode.put("x", 50);
        startNode.put("y", 150);
        startNode.put("status", "completed");
        nodes.add(startNode);

        int x = 180;
        String lastNodeId = "start";

        for (int i = 0; i < disposals.size(); i++) {
            WarningDisposal disposal = disposals.get(i);
            String nodeId = "task_" + i;
            String typeName = DISPOSAL_TYPE_MAP.getOrDefault(disposal.getDisposalType(), "处置");

            Map<String, Object> taskNode = new HashMap<>();
            taskNode.put("id", nodeId);
            taskNode.put("name", typeName);
            taskNode.put("type", "userTask");
            taskNode.put("x", x);
            taskNode.put("y", 150);
            taskNode.put("status", "completed");
            taskNode.put("disposalUser", disposal.getDisposalUser());
            taskNode.put("disposalTime", disposal.getCreateTime() != null ? 
                    disposal.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null);
            taskNode.put("disposalId", disposal.getDisposalId());
            nodes.add(taskNode);

            Map<String, Object> edge = new HashMap<>();
            edge.put("source", lastNodeId);
            edge.put("target", nodeId);
            edge.put("label", "");
            edge.put("status", "completed");
            edges.add(edge);

            lastNodeId = nodeId;
            x += 180;
        }

        String status = warning.getStatus();
        String currentStatus = "waiting";
        if ("CLOSED".equals(status) || "HANDLED".equals(status)) {
            currentStatus = "completed";
        } else if ("PROCESSING".equals(status) || "PENDING".equals(status) || "RELEASED".equals(status)) {
            currentStatus = "active";
        }

        Map<String, Object> endNode = new HashMap<>();
        endNode.put("id", "end");
        endNode.put("name", "处置完成");
        endNode.put("type", "endEvent");
        endNode.put("x", x);
        endNode.put("y", 150);
        endNode.put("status", currentStatus);
        nodes.add(endNode);

        if (!disposals.isEmpty()) {
            Map<String, Object> lastEdge = new HashMap<>();
            lastEdge.put("source", lastNodeId);
            lastEdge.put("target", "end");
            lastEdge.put("label", "");
            lastEdge.put("status", currentStatus);
            edges.add(lastEdge);
        }

        result.put("nodes", nodes);
        result.put("edges", edges);
        result.put("warningId", warningId);
        result.put("warningName", warning.getWarningName());
        result.put("warningNo", warning.getWarningNo());
        result.put("status", warning.getStatus());
        result.put("totalTasks", disposals.size());
        result.put("processDefinitionName", "预警处置流程");

        return result;
    }

    @Override
    public Map<String, Object> getDisposalDetail(String disposalId) {
        WarningDisposal disposal = warningDisposalMapper.selectById(disposalId);
        if (disposal == null) {
            return null;
        }

        Map<String, Object> result = new HashMap<>();
        result.put("disposalId", disposal.getDisposalId());
        result.put("warningId", disposal.getWarningId());
        result.put("disposalType", disposal.getDisposalType());
        result.put("disposalTypeName", DISPOSAL_TYPE_MAP.getOrDefault(disposal.getDisposalType(), "未知"));
        result.put("oldLevel", disposal.getOldLevel());
        result.put("newLevel", disposal.getNewLevel());
        result.put("disposalUser", disposal.getDisposalUser());
        result.put("disposalContent", disposal.getDisposalContent());
        result.put("supervisionUser", disposal.getSupervisionUser());
        result.put("supervisionContent", disposal.getSupervisionContent());
        result.put("notificationType", disposal.getNotificationType());
        result.put("createTime", disposal.getCreateTime() != null ? 
                disposal.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null);

        return result;
    }

    @Override
    public Map<String, Object> getProcessStatistics(String warningId) {
        Map<String, Object> result = new HashMap<>();

        List<WarningDisposal> disposals = getDisposalProcess(warningId);
        EarlyWarning warning = earlyWarningMapper.selectById(warningId);

        result.put("warningId", warningId);
        result.put("warningName", warning != null ? warning.getWarningName() : null);
        result.put("totalDisposals", disposals.size());

        Map<String, Integer> typeCount = new HashMap<>();
        for (WarningDisposal disposal : disposals) {
            String type = disposal.getDisposalType();
            typeCount.put(type, typeCount.getOrDefault(type, 0) + 1);
        }
        result.put("typeDistribution", typeCount);

        Set<String> handlers = new HashSet<>();
        for (WarningDisposal disposal : disposals) {
            if (disposal.getDisposalUser() != null) {
                handlers.add(disposal.getDisposalUser());
            }
        }
        result.put("handlerCount", handlers.size());

        if (!disposals.isEmpty()) {
            result.put("firstDisposalTime", disposals.get(0).getCreateTime() != null ?
                    disposals.get(0).getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null);
            result.put("lastDisposalTime", disposals.get(disposals.size() - 1).getCreateTime() != null ?
                    disposals.get(disposals.size() - 1).getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null);
        }

        return result;
    }

    /**
     * 截断附件类型到 DB 列宽（varchar(64)）以内，避免 Data too long 异常
     */
    private static final int ATTACHMENT_TYPE_MAX_LEN = 64;

    private String truncateAttachmentType(String contentType) {
        if (contentType == null || contentType.isEmpty()) {
            return contentType;
        }
        if (contentType.length() <= ATTACHMENT_TYPE_MAX_LEN) {
            return contentType;
        }
        return contentType.substring(0, ATTACHMENT_TYPE_MAX_LEN);
    }
}
