package com.njcn.gather.tool.addledger.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.njcn.gather.tool.addledger.component.AddLedgerTreeBuilder;
import com.njcn.gather.tool.addledger.mapper.AddLedgerEngineeringMapper;
import com.njcn.gather.tool.addledger.mapper.AddLedgerEquipmentMapper;
import com.njcn.gather.tool.addledger.mapper.AddLedgerLedgerMapper;
import com.njcn.gather.tool.addledger.mapper.AddLedgerLineMapper;
import com.njcn.gather.tool.addledger.mapper.AddLedgerProjectMapper;
import com.njcn.gather.tool.addledger.mapper.AddDeviceUnitMapper;
import com.njcn.gather.tool.addledger.mapper.AddOverlimitMapper;
import com.njcn.gather.tool.addledger.pojo.constant.AddLedgerConst;
import com.njcn.gather.tool.addledger.pojo.param.AddDeviceUnitSaveParam;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerEngineeringSaveParam;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerEquipmentSaveParam;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerLinePathQueryParam;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerLineSaveParam;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerProjectSaveParam;
import com.njcn.gather.tool.addledger.pojo.po.AddDeviceUnit;
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerEngineeringPO;
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerEquipmentPO;
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerLedgerPO;
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerLinePO;
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerProjectPO;
import com.njcn.gather.tool.addledger.pojo.po.AddOverlimitPO;
import com.njcn.gather.tool.addledger.pojo.vo.AddDeviceUnitVO;
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerDetailVO;
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerLinePathVO;
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerTreeNodeVO;
import com.njcn.gather.tool.addledger.service.AddLedgerService;
import com.njcn.gather.tool.addledger.util.AddLedgerIdUtil;
import com.njcn.gather.tool.addledger.util.AddLedgerLineNoUtil;
import com.njcn.gather.tool.addledger.util.COverlimitUtil;
import com.njcn.web.utils.RequestUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 数据台账服务实现。
 */
@Service
@RequiredArgsConstructor
public class AddLedgerServiceImpl implements AddLedgerService {

    private static final int DEFAULT_LINE_PATH_QUERY_LIMIT = 1000;
    private static final int MAX_LINE_PATH_QUERY_LIMIT = 5000;

    private final AddLedgerEngineeringMapper engineeringMapper;
    private final AddLedgerProjectMapper projectMapper;
    private final AddLedgerEquipmentMapper equipmentMapper;
    private final AddLedgerLineMapper lineMapper;
    private final AddLedgerLedgerMapper ledgerMapper;
    private final AddDeviceUnitMapper deviceUnitMapper;
    private final AddOverlimitMapper overlimitMapper;
    private final AddLedgerTreeBuilder treeBuilder;

    @Override
    public List<AddLedgerTreeNodeVO> tree(String keyword) {
        return treeBuilder.buildTree(ledgerMapper.selectTree(trimToNull(keyword)));
    }

    @Override
    public AddLedgerDetailVO detail(String id, Integer level) {
        AddLedgerLedgerPO ledger = requireLedger(id, level, levelName(level) + "节点");
        if (AddLedgerConst.LEVEL_ENGINEERING == level) {
            return buildEngineeringDetail(ledger, requireEngineering(id));
        }
        if (AddLedgerConst.LEVEL_PROJECT == level) {
            return buildProjectDetail(ledger, requireProject(id));
        }
        if (AddLedgerConst.LEVEL_EQUIPMENT == level) {
            return buildEquipmentDetail(ledger, requireEquipment(id));
        }
        if (AddLedgerConst.LEVEL_LINE == level) {
            return buildLineDetail(ledger, requireLine(id));
        }
        throw new IllegalArgumentException("不支持的台账层级");
    }

    @Override
    @Transactional
    public AddLedgerDetailVO saveEngineering(AddLedgerEngineeringSaveParam param) {
        String name = requireText(param == null ? null : param.getName(), "工程名称不能为空");
        boolean create = isBlank(param.getId());
        String id = create ? AddLedgerIdUtil.nextId() : param.getId().trim();

        AddLedgerEngineeringPO engineering = create ? new AddLedgerEngineeringPO() : requireEngineering(id);
        engineering.setId(id);
        engineering.setName(name);
        engineering.setProvince(trimToNull(param.getProvince()));
        engineering.setCity(trimToNull(param.getCity()));
        engineering.setDescription(trimToNull(param.getDescription()));
        if (create) {
            engineering.setStatus(AddLedgerConst.STATE_NORMAL);
            engineering.setSort(0);
            engineeringMapper.insert(engineering);
            saveLedger(id, AddLedgerConst.ROOT_PARENT_ID, AddLedgerConst.ROOT_PARENT_ID, name, AddLedgerConst.LEVEL_ENGINEERING);
        } else {
            engineeringMapper.updateById(engineering);
            updateLedgerName(id, AddLedgerConst.LEVEL_ENGINEERING, name);
        }
        return detail(id, AddLedgerConst.LEVEL_ENGINEERING);
    }

    @Override
    @Transactional
    public AddLedgerDetailVO saveProject(AddLedgerProjectSaveParam param) {
        String name = requireText(param == null ? null : param.getName(), "项目名称不能为空");
        boolean create = isBlank(param.getId());
        String id = create ? AddLedgerIdUtil.nextId() : param.getId().trim();
        AddLedgerLedgerPO parentLedger;
        if (create) {
            parentLedger = requireLedger(param.getEngineeringId(), AddLedgerConst.LEVEL_ENGINEERING, "父级工程节点");
        } else {
            AddLedgerLedgerPO projectLedger = requireLedger(id, AddLedgerConst.LEVEL_PROJECT, "项目节点");
            parentLedger = requireLedger(projectLedger.getPid(), AddLedgerConst.LEVEL_ENGINEERING, "项目所属工程节点");
        }

        AddLedgerProjectPO project = create ? new AddLedgerProjectPO() : requireProject(id);
        project.setId(id);
        project.setName(name);
        project.setArea(trimToNull(param.getArea()));
        project.setDescription(trimToNull(param.getDescription()));
        if (create) {
            project.setStatus(AddLedgerConst.STATE_NORMAL);
            project.setSort(0);
            projectMapper.insert(project);
            saveLedger(id, parentLedger.getId(), buildChildPids(parentLedger), name, AddLedgerConst.LEVEL_PROJECT);
        } else {
            projectMapper.updateById(project);
            updateLedgerName(id, AddLedgerConst.LEVEL_PROJECT, name);
        }
        return detail(id, AddLedgerConst.LEVEL_PROJECT);
    }

    @Override
    @Transactional
    public AddLedgerDetailVO saveEquipment(AddLedgerEquipmentSaveParam param) {
        validateEquipmentParam(param);
        boolean create = isBlank(param.getId());
        String id = create ? AddLedgerIdUtil.nextId() : param.getId().trim();
        AddLedgerLedgerPO projectLedger;
        if (create) {
            projectLedger = requireLedger(param.getProjectId(), AddLedgerConst.LEVEL_PROJECT, "父级项目节点");
        } else {
            AddLedgerLedgerPO equipmentLedger = requireLedger(id, AddLedgerConst.LEVEL_EQUIPMENT, "设备节点");
            projectLedger = requireLedger(equipmentLedger.getPid(), AddLedgerConst.LEVEL_PROJECT, "设备所属项目节点");
        }
        AddLedgerLedgerPO engineeringLedger = requireLedger(projectLedger.getPid(), AddLedgerConst.LEVEL_ENGINEERING, "项目所属工程节点");

        AddLedgerEquipmentPO equipment = create ? new AddLedgerEquipmentPO() : requireEquipment(id);
        equipment.setId(id);
        equipment.setName(param.getName().trim());
        equipment.setNdid(param.getNdid().trim());
        equipment.setMac(param.getMac().trim());
        equipment.setDevType(trimToNull(param.getDevType()));
        equipment.setDevModel(param.getDevModel().trim());
        equipment.setDevAccessMethod(trimToNull(param.getDevAccessMethod()));
        equipment.setNodeId(trimToNull(param.getNodeId()));
        equipment.setNodeProcess(param.getNodeProcess());
        equipment.setUpgrade(param.getUpgrade() == null ? AddLedgerConst.DISABLE : param.getUpgrade());
        equipment.setAssociatedEngineering(engineeringLedger.getId());
        equipment.setAssociatedProject(projectLedger.getId());
        if (create) {
            equipment.setRunStatus(AddLedgerConst.EQUIPMENT_RUN_STATUS_OFFLINE);
            equipment.setStatus(AddLedgerConst.EQUIPMENT_STATUS_UNREGISTERED);
            equipment.setProcess(AddLedgerConst.EQUIPMENT_PROCESS_RUNNING);
            equipment.setUsageStatus(AddLedgerConst.ENABLE);
            equipment.setSort(0);
            equipmentMapper.insert(equipment);
            saveDefaultDeviceUnit(id);
            saveLedger(id, projectLedger.getId(), buildChildPids(projectLedger), equipment.getName(), AddLedgerConst.LEVEL_EQUIPMENT);
        } else {
            equipmentMapper.updateById(equipment);
            updateLedgerName(id, AddLedgerConst.LEVEL_EQUIPMENT, equipment.getName());
        }
        return detail(id, AddLedgerConst.LEVEL_EQUIPMENT);
    }

    @Override
    public AddDeviceUnitVO getDeviceUnit(String devId) {
        String deviceId = requireText(devId, "设备 ID 不能为空");
        requireEquipment(deviceId);
        AddDeviceUnit unit = deviceUnitMapper.selectById(deviceId);
        if (unit == null) {
            unit = buildDefaultDeviceUnit(deviceId);
        }
        return buildDeviceUnitVO(unit);
    }

    @Override
    @Transactional
    public AddDeviceUnitVO saveDeviceUnit(AddDeviceUnitSaveParam param) {
        if (param == null) {
            throw new IllegalArgumentException("设备单位参数不能为空");
        }
        String deviceId = requireText(param.getDevId(), "设备 ID 不能为空");
        requireEquipment(deviceId);
        AddDeviceUnit unit = deviceUnitMapper.selectById(deviceId);
        boolean create = unit == null;
        if (create) {
            unit = buildDefaultDeviceUnit(deviceId);
        }
        applyDeviceUnitParam(unit, param);
        if (create) {
            deviceUnitMapper.insert(unit);
        } else {
            deviceUnitMapper.updateById(unit);
        }
        return buildDeviceUnitVO(unit);
    }

    @Override
    @Transactional
    public AddLedgerDetailVO saveLine(AddLedgerLineSaveParam param) {
        validateLineParam(param);
        boolean create = isBlank(param.getLineId());
        String id = create ? AddLedgerIdUtil.nextId() : param.getLineId().trim();
        AddLedgerLedgerPO equipmentLedger;
        if (create) {
            equipmentLedger = requireLedger(param.getDeviceId(), AddLedgerConst.LEVEL_EQUIPMENT, "父级设备节点");
        } else {
            AddLedgerLedgerPO lineLedger = requireLedger(id, AddLedgerConst.LEVEL_LINE, "测点节点");
            equipmentLedger = requireLedger(lineLedger.getPid(), AddLedgerConst.LEVEL_EQUIPMENT, "测点所属设备节点");
        }
        assertLineNoUnique(equipmentLedger.getId(), param.getLineNo(), create ? null : id);

        AddLedgerLinePO line = create ? new AddLedgerLinePO() : requireLine(id);
        line.setLineId(id);
        line.setName(param.getName().trim());
        line.setDeviceId(equipmentLedger.getId());
        line.setLineNo(param.getLineNo());
        line.setConType(param.getConType());
        line.setVolGrade(param.getVolGrade());
        line.setPosition(trimToNull(param.getPosition()));
        line.setCtRatio(param.getCtRatio());
        line.setCt2Ratio(param.getCt2Ratio());
        line.setPtRatio(param.getPtRatio());
        line.setPt2Ratio(param.getPt2Ratio());
        line.setShortCircuitCapacity(param.getShortCircuitCapacity());
        line.setDevCapacity(param.getDevCapacity());
        line.setBasicCapacity(param.getBasicCapacity());
        line.setProtocolCapacity(param.getProtocolCapacity());
        line.setLineType(param.getLineType() == null ? AddLedgerConst.LINE_TYPE_MAIN : param.getLineType());
        line.setMonitorObj(trimToNull(param.getMonitorObj()));
        line.setIsGovern(param.getIsGovern() == null ? AddLedgerConst.DISABLE : param.getIsGovern());
        line.setMonitorUser(trimToNull(param.getMonitorUser()));
        line.setIsImportant(param.getIsImportant() == null ? AddLedgerConst.DISABLE : param.getIsImportant());
        if (create) {
            line.setStatus(AddLedgerConst.STATE_NORMAL);
            line.setRunStatus(AddLedgerConst.LINE_RUN_STATUS_RUNNING);
            line.setLineInterval(AddLedgerConst.LINE_INTERVAL_DEFAULT);
            line.setLineLogLevel(AddLedgerConst.LOG_LEVEL_WARN);
            lineMapper.insert(line);
            saveLedger(id, equipmentLedger.getId(), buildChildPids(equipmentLedger), line.getName(), AddLedgerConst.LEVEL_LINE);
        } else {
            lineMapper.updateById(line);
            updateLedgerName(id, AddLedgerConst.LEVEL_LINE, line.getName());
        }
        saveOrUpdateOverlimit(line);
        return detail(id, AddLedgerConst.LEVEL_LINE);
    }

    @Override
    public List<Integer> availableLineNos(String deviceId, String lineId) {
        AddLedgerLedgerPO equipmentLedger = requireLedger(deviceId, AddLedgerConst.LEVEL_EQUIPMENT, "设备节点");
        List<Integer> usedLineNos = lineMapper.selectUsedLineNos(equipmentLedger.getId(), trimToNull(lineId));
        return AddLedgerLineNoUtil.resolveAvailableLineNos(usedLineNos, null);
    }

    @Override
    public AddOverlimitPO getLineOverlimit(String lineId) {
        AddLedgerLinePO line = requireLine(lineId);
        return overlimitMapper.selectById(line.getLineId());
    }

    @Override
    public Map<String, AddLedgerLinePathVO> listLinePathByLineIds(List<String> lineIds) {
        List<String> normalizedLineIds = normalizeIds(lineIds);
        if (normalizedLineIds.isEmpty()) {
            return Collections.emptyMap();
        }
        List<AddLedgerLinePathVO> linePaths = lineMapper.selectLinePathByLineIds(normalizedLineIds);
        Map<String, AddLedgerLinePathVO> result = new LinkedHashMap<String, AddLedgerLinePathVO>();
        for (AddLedgerLinePathVO linePath : linePaths) {
            if (linePath != null && !isBlank(linePath.getLineId())) {
                result.put(linePath.getLineId(), linePath);
            }
        }
        return result;
    }

    @Override
    public List<String> listLineIdsByPathQuery(AddLedgerLinePathQueryParam param) {
        if (!hasPathKeyword(param)) {
            return Collections.emptyList();
        }
        AddLedgerLinePathQueryParam queryParam = new AddLedgerLinePathQueryParam();
        queryParam.setEngineeringName(trimToNull(param.getEngineeringName()));
        queryParam.setProjectName(trimToNull(param.getProjectName()));
        queryParam.setEquipmentName(trimToNull(param.getEquipmentName()));
        queryParam.setLineName(trimToNull(param.getLineName()));
        queryParam.setLimit(normalizeLimit(param.getLimit()));
        List<AddLedgerLinePathVO> linePaths = lineMapper.selectLinePathByQuery(queryParam);
        List<String> lineIds = new ArrayList<String>();
        for (AddLedgerLinePathVO linePath : linePaths) {
            if (linePath != null && !isBlank(linePath.getLineId())) {
                lineIds.add(linePath.getLineId());
            }
        }
        return lineIds;
    }

    @Override
    @Transactional
    public boolean deleteNode(String id, Integer level) {
        requireLedger(id, level, levelName(level) + "节点");
        List<AddLedgerLedgerPO> subtree = ledgerMapper.selectActiveSubtree(id);
        if (subtree.isEmpty()) {
            return false;
        }
        List<String> engineeringIds = new ArrayList<String>();
        List<String> projectIds = new ArrayList<String>();
        List<String> equipmentIds = new ArrayList<String>();
        List<String> lineIds = new ArrayList<String>();
        List<String> ledgerIds = new ArrayList<String>();
        for (AddLedgerLedgerPO node : subtree) {
            ledgerIds.add(node.getId());
            if (AddLedgerConst.LEVEL_ENGINEERING == node.getLevel()) {
                engineeringIds.add(node.getId());
            } else if (AddLedgerConst.LEVEL_PROJECT == node.getLevel()) {
                projectIds.add(node.getId());
            } else if (AddLedgerConst.LEVEL_EQUIPMENT == node.getLevel()) {
                equipmentIds.add(node.getId());
            } else if (AddLedgerConst.LEVEL_LINE == node.getLevel()) {
                lineIds.add(node.getId());
            }
        }
        String updateBy = currentUserId();
        if (!lineIds.isEmpty()) {
            lineMapper.softDeleteByIds(lineIds, updateBy);
            overlimitMapper.deleteBatchIds(lineIds);
        }
        if (!equipmentIds.isEmpty()) {
            equipmentMapper.softDeleteByIds(equipmentIds, updateBy);
        }
        if (!projectIds.isEmpty()) {
            projectMapper.softDeleteByIds(projectIds, updateBy);
        }
        if (!engineeringIds.isEmpty()) {
            engineeringMapper.softDeleteByIds(engineeringIds, updateBy);
        }
        ledgerMapper.softDeleteByIds(ledgerIds, updateBy);
        return true;
    }

    private void validateEquipmentParam(AddLedgerEquipmentSaveParam param) {
        if (param == null) {
            throw new IllegalArgumentException("设备参数不能为空");
        }
        requireText(param.getName(), "设备名称不能为空");
        requireText(param.getNdid(), "设备 ndid 不能为空");
        requireText(param.getMac(), "设备 mac 不能为空");
        requireText(param.getDevModel(), "设备 dev_model 不能为空");
    }

    private void validateLineParam(AddLedgerLineSaveParam param) {
        if (param == null) {
            throw new IllegalArgumentException("测点参数不能为空");
        }
        requireText(param.getName(), "测点名称不能为空");
        if (param.getLineNo() == null
                || param.getLineNo() < AddLedgerConst.MIN_LINE_NO
                || param.getLineNo() > AddLedgerConst.MAX_LINE_NO) {
            throw new IllegalArgumentException("line_no 必须在 1-20 之间");
        }
        if (!AddLedgerConst.CON_TYPES.contains(param.getConType())) {
            throw new IllegalArgumentException("conType 只能是 0、1、2");
        }
        if (!containsVolGrade(param.getVolGrade())) {
            throw new IllegalArgumentException("vol_grade 只能是 0.38、10、35、110、220、500");
        }
        requireNonNegative(param.getCtRatio(), "ct_ratio 不能为空且不能为负数");
        requireNonNegative(param.getCt2Ratio(), "ct2_ratio 不能为空且不能为负数");
        requireNonNegative(param.getPtRatio(), "pt_ratio 不能为空且不能为负数");
        requireNonNegative(param.getPt2Ratio(), "pt2_ratio 不能为空且不能为负数");
        requireNonNegativeIfPresent(param.getShortCircuitCapacity(), "short_circuit_capacity 不能为负数");
        requireNonNegativeIfPresent(param.getDevCapacity(), "dev_capacity 不能为负数");
        requireNonNegativeIfPresent(param.getBasicCapacity(), "basic_capacity 不能为负数");
        requireNonNegativeIfPresent(param.getProtocolCapacity(), "protocol_capacity 不能为负数");
        if (param.getLineType() != null && !AddLedgerConst.LINE_TYPES.contains(param.getLineType())) {
            throw new IllegalArgumentException("lineType 只能是 0 或 1");
        }
    }

    private void assertLineNoUnique(String deviceId, Integer lineNo, String lineId) {
        int count = lineMapper.countActiveLineNo(deviceId, lineNo, lineId);
        if (count > 0) {
            throw new IllegalArgumentException("同设备下 line_no 不可重复");
        }
    }

    private AddLedgerLedgerPO requireLedger(String id, Integer level, String nodeName) {
        String nodeId = requireText(id, "台账节点 ID 不能为空");
        if (level == null) {
            throw new IllegalArgumentException("台账节点层级不能为空");
        }
        AddLedgerLedgerPO ledger = ledgerMapper.selectActiveNode(nodeId, level);
        if (ledger == null) {
            throwLedgerNotActive(nodeId, level, nodeName);
        }
        return ledger;
    }

    private void throwLedgerNotActive(String id, Integer expectedLevel, String nodeName) {
        AddLedgerLedgerPO ledger = ledgerMapper.selectNodeById(id);
        String context = isBlank(nodeName) ? "台账节点" : nodeName;
        if (ledger == null) {
            if (Integer.valueOf(AddLedgerConst.LEVEL_LINE).equals(expectedLevel)) {
                throw new IllegalArgumentException(context + "不存在，id=" + id
                        + "。如果是新增监测点，请不要传 lineId；如果是编辑监测点，请传已存在的测点 ID");
            }
            throw new IllegalArgumentException(context + "不存在，id=" + id + "，期望层级=" + expectedLevel);
        }
        if (!expectedLevel.equals(ledger.getLevel())) {
            throw new IllegalArgumentException(context + "层级不匹配，id=" + id
                    + "，实际层级=" + ledger.getLevel() + "，期望层级=" + expectedLevel);
        }
        if (!Integer.valueOf(AddLedgerConst.STATE_NORMAL).equals(ledger.getState())) {
            throw new IllegalArgumentException(context + "已删除，id=" + id + "，State=" + ledger.getState());
        }
        throw new IllegalArgumentException(context + "不存在或已删除，id=" + id + "，期望层级=" + expectedLevel);
    }

    private AddLedgerEngineeringPO requireEngineering(String id) {
        AddLedgerEngineeringPO engineering = engineeringMapper.selectOne(new LambdaQueryWrapper<AddLedgerEngineeringPO>()
                .eq(AddLedgerEngineeringPO::getId, id)
                .eq(AddLedgerEngineeringPO::getStatus, AddLedgerConst.STATE_NORMAL));
        if (engineering == null) {
            throw new IllegalArgumentException("工程不存在或已删除");
        }
        return engineering;
    }

    private AddLedgerProjectPO requireProject(String id) {
        AddLedgerProjectPO project = projectMapper.selectOne(new LambdaQueryWrapper<AddLedgerProjectPO>()
                .eq(AddLedgerProjectPO::getId, id)
                .eq(AddLedgerProjectPO::getStatus, AddLedgerConst.STATE_NORMAL));
        if (project == null) {
            throw new IllegalArgumentException("项目不存在或已删除");
        }
        return project;
    }

    private AddLedgerEquipmentPO requireEquipment(String id) {
        AddLedgerEquipmentPO equipment = equipmentMapper.selectOne(new LambdaQueryWrapper<AddLedgerEquipmentPO>()
                .eq(AddLedgerEquipmentPO::getId, id)
                .ne(AddLedgerEquipmentPO::getRunStatus, AddLedgerConst.EQUIPMENT_RUN_STATUS_DELETED));
        if (equipment == null) {
            throw new IllegalArgumentException("设备不存在或已删除");
        }
        return equipment;
    }

    private AddLedgerLinePO requireLine(String id) {
        AddLedgerLinePO line = lineMapper.selectOne(new LambdaQueryWrapper<AddLedgerLinePO>()
                .eq(AddLedgerLinePO::getLineId, id)
                .eq(AddLedgerLinePO::getStatus, AddLedgerConst.STATE_NORMAL));
        if (line == null) {
            throw new IllegalArgumentException("测点不存在或已删除");
        }
        return line;
    }

    private void saveLedger(String id, String pid, String pids, String name, Integer level) {
        AddLedgerLedgerPO ledger = new AddLedgerLedgerPO();
        ledger.setId(id);
        ledger.setPid(pid);
        ledger.setPids(pids);
        ledger.setName(name);
        ledger.setLevel(level);
        ledger.setSort(0);
        ledger.setState(AddLedgerConst.STATE_NORMAL);
        ledgerMapper.insert(ledger);
    }

    private void saveDefaultDeviceUnit(String devId) {
        deviceUnitMapper.insert(buildDefaultDeviceUnit(devId));
    }

    private AddDeviceUnit buildDefaultDeviceUnit(String devId) {
        AddDeviceUnit unit = new AddDeviceUnit();
        unit.setDevId(devId);
        return unit;
    }

    private void updateLedgerName(String id, Integer level, String name) {
        AddLedgerLedgerPO ledger = requireLedger(id, level, levelName(level) + "节点");
        ledger.setName(name);
        ledgerMapper.updateById(ledger);
    }

    private String buildChildPids(AddLedgerLedgerPO parent) {
        return parent.getPids() + "," + parent.getId();
    }

    private AddLedgerDetailVO buildEngineeringDetail(AddLedgerLedgerPO ledger, AddLedgerEngineeringPO engineering) {
        AddLedgerDetailVO detail = buildBaseDetail(ledger);
        detail.setName(engineering.getName());
        detail.setProvince(engineering.getProvince());
        detail.setCity(engineering.getCity());
        detail.setDescription(engineering.getDescription());
        return detail;
    }

    private AddLedgerDetailVO buildProjectDetail(AddLedgerLedgerPO ledger, AddLedgerProjectPO project) {
        AddLedgerDetailVO detail = buildBaseDetail(ledger);
        detail.setName(project.getName());
        detail.setArea(project.getArea());
        detail.setDescription(project.getDescription());
        return detail;
    }

    private AddLedgerDetailVO buildEquipmentDetail(AddLedgerLedgerPO ledger, AddLedgerEquipmentPO equipment) {
        AddLedgerDetailVO detail = buildBaseDetail(ledger);
        detail.setName(equipment.getName());
        detail.setNdid(equipment.getNdid());
        detail.setMac(equipment.getMac());
        detail.setDevType(equipment.getDevType());
        detail.setDevModel(equipment.getDevModel());
        detail.setDevAccessMethod(equipment.getDevAccessMethod());
        detail.setNodeId(equipment.getNodeId());
        detail.setNodeProcess(equipment.getNodeProcess());
        detail.setUpgrade(equipment.getUpgrade());
        return detail;
    }

    private AddLedgerDetailVO buildLineDetail(AddLedgerLedgerPO ledger, AddLedgerLinePO line) {
        AddLedgerDetailVO detail = buildBaseDetail(ledger);
        detail.setName(line.getName());
        detail.setLineNo(line.getLineNo());
        detail.setConType(line.getConType());
        detail.setVolGrade(line.getVolGrade());
        detail.setPosition(line.getPosition());
        detail.setCtRatio(line.getCtRatio());
        detail.setCt2Ratio(line.getCt2Ratio());
        detail.setPtRatio(line.getPtRatio());
        detail.setPt2Ratio(line.getPt2Ratio());
        detail.setShortCircuitCapacity(line.getShortCircuitCapacity());
        detail.setDevCapacity(line.getDevCapacity());
        detail.setBasicCapacity(line.getBasicCapacity());
        detail.setProtocolCapacity(line.getProtocolCapacity());
        detail.setLineType(AddLedgerConst.LINE_TYPE_MAIN);
        detail.setOverlimit(overlimitMapper.selectById(line.getLineId()));
        detail.setMonitorObj(line.getMonitorObj());
        detail.setIsGovern(line.getIsGovern());
        detail.setMonitorUser(line.getMonitorUser());
        detail.setIsImportant(line.getIsImportant());
        return detail;
    }

    private void saveOrUpdateOverlimit(AddLedgerLinePO line) {
        AddOverlimitPO overlimit = COverlimitUtil.globalAssemble(
                toFloat(line.getVolGrade()),
                toFloat(line.getProtocolCapacity()),
                toFloat(line.getDevCapacity()),
                toFloat(line.getShortCircuitCapacity()),
                null,
                line.getLineType() == null ? AddLedgerConst.LINE_TYPE_MAIN : line.getLineType());
        overlimit.setId(line.getLineId());
        if (overlimitMapper.selectById(line.getLineId()) == null) {
            overlimitMapper.insert(overlimit);
        } else {
            overlimitMapper.updateById(overlimit);
        }
    }

    private Float toFloat(BigDecimal value) {
        return value == null ? null : value.floatValue();
    }

    private void applyDeviceUnitParam(AddDeviceUnit unit, AddDeviceUnitSaveParam param) {
        unit.setUnitFrequency(defaultIfBlank(param.getUnitFrequency(), unit.getUnitFrequency()));
        unit.setUnitFrequencyDev(defaultIfBlank(param.getUnitFrequencyDev(), unit.getUnitFrequencyDev()));
        unit.setPhaseVoltage(defaultIfBlank(param.getPhaseVoltage(), unit.getPhaseVoltage()));
        unit.setLineVoltage(defaultIfBlank(param.getLineVoltage(), unit.getLineVoltage()));
        unit.setVoltageDev(defaultIfBlank(param.getVoltageDev(), unit.getVoltageDev()));
        unit.setUvoltageDev(defaultIfBlank(param.getUvoltageDev(), unit.getUvoltageDev()));
        unit.setIeffective(defaultIfBlank(param.getIeffective(), unit.getIeffective()));
        unit.setSingleP(defaultIfBlank(param.getSingleP(), unit.getSingleP()));
        unit.setSingleViewP(defaultIfBlank(param.getSingleViewP(), unit.getSingleViewP()));
        unit.setSingleNoP(defaultIfBlank(param.getSingleNoP(), unit.getSingleNoP()));
        unit.setTotalActiveP(defaultIfBlank(param.getTotalActiveP(), unit.getTotalActiveP()));
        unit.setTotalViewP(defaultIfBlank(param.getTotalViewP(), unit.getTotalViewP()));
        unit.setTotalNoP(defaultIfBlank(param.getTotalNoP(), unit.getTotalNoP()));
        unit.setVfundEffective(defaultIfBlank(param.getVfundEffective(), unit.getVfundEffective()));
        unit.setIfund(defaultIfBlank(param.getIfund(), unit.getIfund()));
        unit.setFundActiveP(defaultIfBlank(param.getFundActiveP(), unit.getFundActiveP()));
        unit.setFundNoP(defaultIfBlank(param.getFundNoP(), unit.getFundNoP()));
        unit.setVdistortion(defaultIfBlank(param.getVdistortion(), unit.getVdistortion()));
        unit.setVharmonicRate(defaultIfBlank(param.getVharmonicRate(), unit.getVharmonicRate()));
        unit.setIharmonic(defaultIfBlank(param.getIharmonic(), unit.getIharmonic()));
        unit.setPharmonic(defaultIfBlank(param.getPharmonic(), unit.getPharmonic()));
        unit.setIiharmonic(defaultIfBlank(param.getIiharmonic(), unit.getIiharmonic()));
        unit.setPositiveV(defaultIfBlank(param.getPositiveV(), unit.getPositiveV()));
        unit.setNoPositiveV(defaultIfBlank(param.getNoPositiveV(), unit.getNoPositiveV()));
    }

    private AddDeviceUnitVO buildDeviceUnitVO(AddDeviceUnit unit) {
        AddDeviceUnitVO vo = new AddDeviceUnitVO();
        vo.setDevId(unit.getDevId());
        vo.setUnitFrequency(unit.getUnitFrequency());
        vo.setUnitFrequencyDev(unit.getUnitFrequencyDev());
        vo.setPhaseVoltage(unit.getPhaseVoltage());
        vo.setLineVoltage(unit.getLineVoltage());
        vo.setVoltageDev(unit.getVoltageDev());
        vo.setUvoltageDev(unit.getUvoltageDev());
        vo.setIeffective(unit.getIeffective());
        vo.setSingleP(unit.getSingleP());
        vo.setSingleViewP(unit.getSingleViewP());
        vo.setSingleNoP(unit.getSingleNoP());
        vo.setTotalActiveP(unit.getTotalActiveP());
        vo.setTotalViewP(unit.getTotalViewP());
        vo.setTotalNoP(unit.getTotalNoP());
        vo.setVfundEffective(unit.getVfundEffective());
        vo.setIfund(unit.getIfund());
        vo.setFundActiveP(unit.getFundActiveP());
        vo.setFundNoP(unit.getFundNoP());
        vo.setVdistortion(unit.getVdistortion());
        vo.setVharmonicRate(unit.getVharmonicRate());
        vo.setIharmonic(unit.getIharmonic());
        vo.setPharmonic(unit.getPharmonic());
        vo.setIiharmonic(unit.getIiharmonic());
        vo.setPositiveV(unit.getPositiveV());
        vo.setNoPositiveV(unit.getNoPositiveV());
        return vo;
    }

    private AddLedgerDetailVO buildBaseDetail(AddLedgerLedgerPO ledger) {
        AddLedgerDetailVO detail = new AddLedgerDetailVO();
        detail.setId(ledger.getId());
        detail.setLevel(ledger.getLevel());
        detail.setParentId(ledger.getPid());
        detail.setParentIds(ledger.getPids());
        detail.setSort(ledger.getSort());
        detail.setName(ledger.getName());
        return detail;
    }

    private boolean containsVolGrade(BigDecimal volGrade) {
        if (volGrade == null) {
            return false;
        }
        for (BigDecimal supported : AddLedgerConst.VOL_GRADES) {
            if (supported.compareTo(volGrade) == 0) {
                return true;
            }
        }
        return false;
    }

    private void requireNonNegative(BigDecimal value, String message) {
        if (value == null || value.compareTo(BigDecimal.ZERO) < 0) {
            throw new IllegalArgumentException(message);
        }
    }

    private void requireNonNegativeIfPresent(BigDecimal value, String message) {
        if (value != null && value.compareTo(BigDecimal.ZERO) < 0) {
            throw new IllegalArgumentException(message);
        }
    }

    private String requireText(String value, String message) {
        String text = trimToNull(value);
        if (text == null) {
            throw new IllegalArgumentException(message);
        }
        return text;
    }

    private String trimToNull(String value) {
        if (value == null) {
            return null;
        }
        String trimmed = value.trim();
        return trimmed.isEmpty() ? null : trimmed;
    }

    private String defaultIfBlank(String value, String defaultValue) {
        String text = trimToNull(value);
        return text == null ? defaultValue : text;
    }

    private boolean isBlank(String value) {
        return trimToNull(value) == null;
    }

    private String levelName(Integer level) {
        if (Integer.valueOf(AddLedgerConst.LEVEL_ENGINEERING).equals(level)) {
            return "工程";
        }
        if (Integer.valueOf(AddLedgerConst.LEVEL_PROJECT).equals(level)) {
            return "项目";
        }
        if (Integer.valueOf(AddLedgerConst.LEVEL_EQUIPMENT).equals(level)) {
            return "设备";
        }
        if (Integer.valueOf(AddLedgerConst.LEVEL_LINE).equals(level)) {
            return "测点";
        }
        return "台账";
    }

    private List<String> normalizeIds(List<String> ids) {
        if (ids == null || ids.isEmpty()) {
            return Collections.emptyList();
        }
        List<String> normalizedIds = new ArrayList<String>();
        for (String id : ids) {
            String normalizedId = trimToNull(id);
            if (normalizedId != null && !normalizedIds.contains(normalizedId)) {
                normalizedIds.add(normalizedId);
            }
        }
        return normalizedIds;
    }

    private boolean hasPathKeyword(AddLedgerLinePathQueryParam param) {
        return param != null
                && (trimToNull(param.getEngineeringName()) != null
                || trimToNull(param.getProjectName()) != null
                || trimToNull(param.getEquipmentName()) != null
                || trimToNull(param.getLineName()) != null);
    }

    private int normalizeLimit(Integer limit) {
        if (limit == null || limit <= 0) {
            return DEFAULT_LINE_PATH_QUERY_LIMIT;
        }
        return Math.min(limit, MAX_LINE_PATH_QUERY_LIMIT);
    }

    private String currentUserId() {
        try {
            String userId = RequestUtil.getUserId();
            return isBlank(userId) ? "未知用户" : userId;
        } catch (Exception e) {
            return "未知用户";
        }
    }
}
