package com.erp.inventory.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.erp.inventory.dto.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.erp.inventory.entity.Stock;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.erp.inventory.entity.StockWarningRecord;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.erp.inventory.entity.StockWarningRule;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.erp.inventory.entity.Warehouse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.erp.inventory.repository.StockRepository;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.erp.inventory.repository.StockWarningRecordRepository;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.erp.inventory.repository.StockWarningRuleRepository;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.erp.inventory.repository.WarehouseRepository;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.erp.inventory.service.StockWarningNotificationService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.erp.inventory.service.StockWarningRuleService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import com.erp.common.core.model.PageResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;/**
 * 库存预警规则服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class StockWarningRuleServiceImpl implements StockWarningRuleService {

    private final StockWarningRuleRepository warningRuleRepository;
    private final StockWarningRecordRepository warningRecordRepository;
    private final StockRepository stockRepository;
    private final WarehouseRepository warehouseRepository;
    private final StockWarningNotificationService notificationService;

    // ==================== 规则管理 ====================

    @Override
    @Transactional
    public StockWarningRule createRule(StockWarningRuleRequest request) {
        // 获取SKU名称
        String skuName = null;
        if (request.getSkuCode() != null && !request.getSkuCode().isEmpty()) {
            Stock stock = stockRepository.findBySkuCodeAndWarehouseId(
                    request.getSkuCode(), request.getWarehouseId());
            if (stock != null) {
                skuName = stock.getSkuName();
            }
        }

        // 获取仓库名称
        String warehouseName = null;
        if (request.getWarehouseId() != null) {
            warehouseName = warehouseRepository.findNameById(request.getWarehouseId());
        }

        StockWarningRule rule = StockWarningRule.builder()
                .ruleName(request.getRuleName())
                .ruleType(request.getRuleType())
                .skuCode(request.getSkuCode())
                .skuName(skuName)
                .warehouseId(request.getWarehouseId())
                .warehouseName(warehouseName)
                .safetyStockMin(request.getSafetyStockMin())
                .safetyStockMax(request.getSafetyStockMax())
                .warningThreshold(request.getWarningThreshold())
                .maxStockThreshold(request.getMaxStockThreshold())
                .enabled(request.getEnabled())
                .notificationMethods(request.getNotificationMethods())
                .notificationEmails(request.getNotificationEmails())
                .dingtalkWebhook(request.getDingtalkWebhook())
                .dingtalkSecret(request.getDingtalkSecret())
                .repeatIntervalMinutes(request.getRepeatIntervalMinutes() != null ? request.getRepeatIntervalMinutes() : 0)
                .remark(request.getRemark())
                .version(0)
                .build();

        warningRuleRepository.insert(rule);
        log.info("创建预警规则成功: id={}, name={}", rule.getId(), rule.getRuleName());
        return rule;
    }

    @Override
    @Transactional
    public StockWarningRule updateRule(Long id, StockWarningRuleRequest request) {
        StockWarningRule rule = warningRuleRepository.selectById(id);
        if (rule == null) {
            throw new RuntimeException("预警规则不存在");
        }

        // 更新字段
        if (request.getRuleName() != null) {
            rule.setRuleName(request.getRuleName());
        }
        if (request.getRuleType() != null) {
            rule.setRuleType(request.getRuleType());
        }
        if (request.getSkuCode() != null) {
            rule.setSkuCode(request.getSkuCode());
        }
        if (request.getWarehouseId() != null) {
            rule.setWarehouseId(request.getWarehouseId());
            rule.setWarehouseName(warehouseRepository.findNameById(request.getWarehouseId()));
        }
        if (request.getSafetyStockMin() != null) {
            rule.setSafetyStockMin(request.getSafetyStockMin());
        }
        if (request.getSafetyStockMax() != null) {
            rule.setSafetyStockMax(request.getSafetyStockMax());
        }
        if (request.getWarningThreshold() != null) {
            rule.setWarningThreshold(request.getWarningThreshold());
        }
        if (request.getMaxStockThreshold() != null) {
            rule.setMaxStockThreshold(request.getMaxStockThreshold());
        }
        if (request.getEnabled() != null) {
            rule.setEnabled(request.getEnabled());
        }
        if (request.getNotificationMethods() != null) {
            rule.setNotificationMethods(request.getNotificationMethods());
        }
        if (request.getNotificationEmails() != null) {
            rule.setNotificationEmails(request.getNotificationEmails());
        }
        if (request.getDingtalkWebhook() != null) {
            rule.setDingtalkWebhook(request.getDingtalkWebhook());
        }
        if (request.getDingtalkSecret() != null) {
            rule.setDingtalkSecret(request.getDingtalkSecret());
        }
        if (request.getRepeatIntervalMinutes() != null) {
            rule.setRepeatIntervalMinutes(request.getRepeatIntervalMinutes());
        }
        if (request.getRemark() != null) {
            rule.setRemark(request.getRemark());
        }

        warningRuleRepository.updateById(rule);
        log.info("更新预警规则成功: id={}", id);
        return rule;
    }

    @Override
    @Transactional
    public void deleteRule(Long id) {
        StockWarningRule rule = warningRuleRepository.selectById(id);
        if (rule == null) {
            throw new RuntimeException("预警规则不存在");
        }
        warningRuleRepository.deleteById(id);
        log.info("删除预警规则: id={}", id);
    }

    @Override
    public StockWarningRuleDTO getRuleById(Long id) {
        StockWarningRule rule = warningRuleRepository.selectById(id);
        if (rule == null) {
            throw new RuntimeException("预警规则不存在");
        }
        return toRuleDTO(rule);
    }

    @Override
    public PageResponse<StockWarningRuleDTO> listRules(String ruleType, String ruleName, Integer enabled,
                                                        Long warehouseId, Integer page, Integer limit) {
        Page<StockWarningRule> pageParam = new Page<>(page, limit);
        IPage<StockWarningRule> rulePage = warningRuleRepository.findByConditions(
                pageParam, ruleType, ruleName, enabled, warehouseId);

        List<StockWarningRuleDTO> dtoList = rulePage.getRecords().stream()
                .map(this::toRuleDTO)
                .collect(Collectors.toList());

        return PageResponse.of(dtoList, rulePage.getTotal(), page, limit);
    }

    @Override
    @Transactional
    public StockWarningRule toggleRule(Long id, Boolean enabled) {
        StockWarningRule rule = warningRuleRepository.selectById(id);
        if (rule == null) {
            throw new RuntimeException("预警规则不存在");
        }
        rule.setEnabled(enabled ? 1 : 0);
        warningRuleRepository.updateById(rule);
        log.info("{}规则: id={}", enabled ? "启用" : "禁用", id);
        return rule;
    }

    // ==================== 规则匹配 ====================

    @Override
    public List<StockWarningRule> getMatchedRules(String skuCode, Long warehouseId) {
        // 获取所有启用的规则
        List<StockWarningRule> allRules = warningRuleRepository.findAllEnabled();

        // 匹配规则：优先精确匹配，其次全局匹配
        return allRules.stream()
                .filter(rule -> {
                    // 规则类型匹配
                    if (rule.getRuleType() == null) return false;

                    // 检查SKU和仓库匹配
                    boolean skuMatch = rule.getSkuCode() == null || rule.getSkuCode().isEmpty()
                            || rule.getSkuCode().equals(skuCode);
                    boolean warehouseMatch = rule.getWarehouseId() == null
                            || rule.getWarehouseId().equals(warehouseId);

                    return skuMatch && warehouseMatch;
                })
                .sorted(Comparator.comparing(StockWarningRule::getSkuCode,
                        Comparator.nullsLast(Comparator.naturalOrder())))
                .collect(Collectors.toList());
    }

    @Override
    public List<StockWarningRule> getAllEnabledRules() {
        return warningRuleRepository.findAllEnabled();
    }

    // ==================== 预警记录 ====================

    @Override
    @Transactional
    public StockWarningRecord createWarningRecord(String skuCode, String skuName, Long warehouseId,
                                                   String warehouseName, StockWarningRule rule,
                                                   Integer currentQuantity, Integer availableQuantity) {
        // 检查是否需要重复预警
        if (rule.getRepeatIntervalMinutes() != null && rule.getRepeatIntervalMinutes() > 0) {
            Integer unresolvedCount = warningRecordRepository.countUnresolvedByRuleIdAndSkuCodeAndWarehouse(
                    rule.getId(), skuCode, warehouseId);
            if (unresolvedCount > 0) {
                log.info("存在未解决的同类预警，跳过创建: skuCode={}, warehouseId={}, ruleId={}",
                        skuCode, warehouseId, rule.getId());
                return null;
            }
        }

        // 计算预警阈值和差值
        Integer warningThreshold = getWarningThreshold(rule, currentQuantity);
        int deficit = calculateDeficit(rule, currentQuantity);

        // 确定预警等级
        String level = determineLevel(rule, currentQuantity, deficit);

        // 构建预警消息
        String message = buildWarningMessage(rule, currentQuantity, availableQuantity, warningThreshold, deficit);

        // 创建预警记录
        StockWarningRecord record = StockWarningRecord.builder()
                .ruleId(rule.getId())
                .ruleName(rule.getRuleName())
                .ruleType(rule.getRuleType())
                .skuCode(skuCode)
                .skuName(skuName)
                .warehouseId(warehouseId)
                .warehouseName(warehouseName)
                .currentQuantity(currentQuantity)
                .availableQuantity(availableQuantity)
                .warningThreshold(warningThreshold)
                .deficit(deficit)
                .level(level)
                .message(message)
                .status(StockWarningRecord.Status.PENDING.getCode())
                .notificationMethod(rule.getNotificationMethods())
                .version(0)
                .build();

        warningRecordRepository.insert(record);
        log.info("创建预警记录成功: id={}, skuCode={}, ruleType={}", record.getId(), skuCode, rule.getRuleType());

        // 发送通知
        if (rule.getNotificationMethods() != null && !rule.getNotificationMethods().isEmpty()) {
            try {
                boolean success = notificationService.sendNotification(record, rule);
                record.setNotificationSuccess(success ? 1 : 0);
                if (!success) {
                    record.setNotificationError("通知发送失败");
                }
                record.setStatus(StockWarningRecord.Status.NOTIFIED.getCode());
                warningRecordRepository.updateById(record);
            } catch (Exception e) {
                log.error("发送预警通知失败: {}", e.getMessage());
                record.setNotificationSuccess(0);
                record.setNotificationError(e.getMessage());
                warningRecordRepository.updateById(record);
            }
        }

        return record;
    }

    private Integer getWarningThreshold(StockWarningRule rule, Integer currentQuantity) {
        return switch (rule.getRuleType()) {
            case "low_stock", "out_of_stock" -> rule.getWarningThreshold() != null ? rule.getWarningThreshold() :
                    (rule.getSafetyStockMin() != null ? rule.getSafetyStockMin() : 0);
            case "high_stock" -> rule.getMaxStockThreshold() != null ? rule.getMaxStockThreshold() :
                    (rule.getSafetyStockMax() != null ? rule.getSafetyStockMax() : Integer.MAX_VALUE);
            default -> rule.getWarningThreshold() != null ? rule.getWarningThreshold() : 0;
        };
    }

    private int calculateDeficit(StockWarningRule rule, Integer currentQuantity) {
        return switch (rule.getRuleType()) {
            case "low_stock", "out_of_stock" -> {
                int threshold = rule.getWarningThreshold() != null ? rule.getWarningThreshold() :
                        (rule.getSafetyStockMin() != null ? rule.getSafetyStockMin() : 0);
                yield Math.max(0, threshold - currentQuantity);
            }
            case "high_stock" -> {
                int threshold = rule.getMaxStockThreshold() != null ? rule.getMaxStockThreshold() :
                        (rule.getSafetyStockMax() != null ? rule.getSafetyStockMax() : Integer.MAX_VALUE);
                yield Math.max(0, currentQuantity - threshold);
            }
            default -> 0;
        };
    }

    private String determineLevel(StockWarningRule rule, Integer currentQuantity, int deficit) {
        // 紧急：库存为0或严重缺货/超货（超过阈值100%以上）
        // 警告：缺货/超货达到阈值的50%-100%
        // 通知：轻微缺货/超货（低于阈值50%）
        int threshold = getWarningThreshold(rule, currentQuantity);
        if (threshold == 0) {
            return currentQuantity == 0 ? StockWarningRecord.Level.CRITICAL.getCode() :
                    StockWarningRecord.Level.WARNING.getCode();
        }

        double ratio = (double) deficit / threshold;
        if (ratio >= 1.0 || currentQuantity == 0) {
            return StockWarningRecord.Level.CRITICAL.getCode();
        } else if (ratio >= 0.5) {
            return StockWarningRecord.Level.WARNING.getCode();
        } else {
            return StockWarningRecord.Level.INFO.getCode();
        }
    }

    private String buildWarningMessage(StockWarningRule rule, Integer currentQuantity,
                                        Integer availableQuantity, Integer warningThreshold, int deficit) {
        String typeLabel = rule.getRuleType() != null ?
                StockWarningRule.RuleType.fromCode(rule.getRuleType()).getLabel() : "库存";

        return switch (rule.getRuleType()) {
            case "low_stock" -> String.format("%s：商品[%s]当前库存%d，可用库存%d，低于预警阈值%d，请及时补货（缺货%d件）",
                    typeLabel, rule.getSkuCode(), currentQuantity, availableQuantity, warningThreshold, deficit);
            case "high_stock" -> String.format("%s：商品[%s]当前库存%d，可用库存%d，超过最高库存上限%d，库存过高（超出%d件）",
                    typeLabel, rule.getSkuCode(), currentQuantity, availableQuantity, warningThreshold, deficit);
            case "out_of_stock" -> String.format("%s：商品[%s]已缺货！当前库存%d，可用库存%d，请立即补货（缺货%d件）",
                    typeLabel, rule.getSkuCode(), currentQuantity, availableQuantity, deficit);
            default -> String.format("%s：商品[%s]库存异常，当前库存%d，请检查", typeLabel, rule.getSkuCode(), currentQuantity);
        };
    }

    @Override
    public PageResponse<StockWarningRecordDTO> listWarningRecords(StockWarningRecordQueryDTO query) {
        Page<StockWarningRecord> pageParam = new Page<>(query.getPage(), query.getLimit());

        LocalDateTime startDateTime = null;
        LocalDateTime endDateTime = null;
        if (query.getStartDate() != null && !query.getStartDate().isEmpty()) {
            startDateTime = LocalDateTime.parse(query.getStartDate() + " 00:00:00",
                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        }
        if (query.getEndDate() != null && !query.getEndDate().isEmpty()) {
            endDateTime = LocalDateTime.parse(query.getEndDate() + " 23:59:59",
                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        }

        IPage<StockWarningRecord> recordPage = warningRecordRepository.findByConditions(
                pageParam, query.getSkuCode(), query.getWarehouseId(), query.getRuleType(),
                query.getStatus(), query.getLevel(), startDateTime, endDateTime);

        List<StockWarningRecordDTO> dtoList = recordPage.getRecords().stream()
                .map(this::toRecordDTO)
                .collect(Collectors.toList());

        return PageResponse.of(dtoList, recordPage.getTotal(), query.getPage(), query.getLimit());
    }

    @Override
    @Transactional
    public StockWarningRecord acknowledgeWarning(Long id) {
        StockWarningRecord record = warningRecordRepository.selectById(id);
        if (record == null) {
            throw new RuntimeException("预警记录不存在");
        }

        record.setStatus(StockWarningRecord.Status.ACKNOWLEDGED.getCode());
        record.setAcknowledgedAt(LocalDateTime.now());
        warningRecordRepository.updateById(record);

        log.info("确认预警: id={}", id);
        return record;
    }

    @Override
    @Transactional
    public StockWarningRecord resolveWarning(Long id, String remark) {
        StockWarningRecord record = warningRecordRepository.selectById(id);
        if (record == null) {
            throw new RuntimeException("预警记录不存在");
        }

        record.setStatus(StockWarningRecord.Status.RESOLVED.getCode());
        record.setResolvedAt(LocalDateTime.now());
        record.setResolvedRemark(remark);
        warningRecordRepository.updateById(record);

        log.info("解决预警: id={}, remark={}", id, remark);
        return record;
    }

    @Override
    @Transactional
    public StockWarningRecord ignoreWarning(Long id) {
        StockWarningRecord record = warningRecordRepository.selectById(id);
        if (record == null) {
            throw new RuntimeException("预警记录不存在");
        }

        record.setStatus(StockWarningRecord.Status.IGNORED.getCode());
        warningRecordRepository.updateById(record);

        log.info("忽略预警: id={}", id);
        return record;
    }

    @Override
    public Integer getPendingWarningCount() {
        return warningRecordRepository.selectCount(
                new QueryWrapper<StockWarningRecord>()
                        .in("status", StockWarningRecord.Status.PENDING.getCode(),
                        StockWarningRecord.Status.NOTIFIED.getCode(),
                        StockWarningRecord.Status.ACKNOWLEDGED.getCode())).intValue();
    }

    // ==================== 预警统计 ====================

    @Override
    public StockWarningStatsDTO getWarningStats(String startDate, String endDate) {
        LocalDateTime startDateTime = LocalDateTime.parse(startDate + " 00:00:00",
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        LocalDateTime endDateTime = LocalDateTime.parse(endDate + " 23:59:59",
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

        // 统计总数
        Integer totalWarnings = warningRecordRepository.countByRuleTypeAndCreatedAtBetween(null, startDateTime, endDateTime);
        Integer pendingWarnings = warningRecordRepository.selectCount(
                new QueryWrapper<StockWarningRecord>()
                        .ge("created_at", startDateTime)
                        .le("created_at", endDateTime)
                        .in("status", StockWarningRecord.Status.PENDING.getCode(),
                        StockWarningRecord.Status.NOTIFIED.getCode(),
                        StockWarningRecord.Status.ACKNOWLEDGED.getCode())).intValue();
        Integer resolvedWarnings = warningRecordRepository.countByStatusAndCreatedAtBetween(
                StockWarningRecord.Status.RESOLVED.getCode(), startDateTime, endDateTime);
        Integer ignoredWarnings = warningRecordRepository.countByStatusAndCreatedAtBetween(
                StockWarningRecord.Status.IGNORED.getCode(), startDateTime, endDateTime);

        // 按规则类型统计
        Integer lowStockWarnings = warningRecordRepository.countByRuleTypeAndCreatedAtBetween(
                StockWarningRule.RuleType.LOW_STOCK.getCode(), startDateTime, endDateTime);
        Integer highStockWarnings = warningRecordRepository.countByRuleTypeAndCreatedAtBetween(
                StockWarningRule.RuleType.HIGH_STOCK.getCode(), startDateTime, endDateTime);
        Integer outOfStockWarnings = warningRecordRepository.countByRuleTypeAndCreatedAtBetween(
                StockWarningRule.RuleType.OUT_OF_STOCK.getCode(), startDateTime, endDateTime);

        // 按等级统计
        Integer criticalWarnings = warningRecordRepository.selectCount(
                new QueryWrapper<StockWarningRecord>()
                        .eq("level", StockWarningRecord.Level.CRITICAL.getCode())
                        .ge("created_at", startDateTime)
                        .le("created_at", endDateTime)).intValue();
        Integer warningWarnings = warningRecordRepository.selectCount(
                new QueryWrapper<StockWarningRecord>()
                        .eq("level", StockWarningRecord.Level.WARNING.getCode())
                        .ge("created_at", startDateTime)
                        .le("created_at", endDateTime)).intValue();
        Integer infoWarnings = warningRecordRepository.selectCount(
                new QueryWrapper<StockWarningRecord>()
                        .eq("level", StockWarningRecord.Level.INFO.getCode())
                        .ge("created_at", startDateTime)
                        .le("created_at", endDateTime)).intValue();

        // 计算解决率
        double resolveRate = totalWarnings > 0 ? (double) resolvedWarnings / totalWarnings * 100 : 0;

        // 计算平均解决时长
        List<StockWarningRecord> resolvedRecords = warningRecordRepository.selectList(
                new QueryWrapper<StockWarningRecord>()
                        .eq("status", StockWarningRecord.Status.RESOLVED.getCode())
                        .ge("created_at", startDateTime)
                        .le("created_at", endDateTime)
                        .isNotNull("resolved_at"));

        double avgResolveTimeMinutes = 0;
        if (!resolvedRecords.isEmpty()) {
            long totalMinutes = resolvedRecords.stream()
                    .mapToLong(r -> ChronoUnit.MINUTES.between(r.getCreatedAt(), r.getResolvedAt()))
                    .sum();
            avgResolveTimeMinutes = (double) totalMinutes / resolvedRecords.size();
        }

        return StockWarningStatsDTO.builder()
                .startDate(startDateTime)
                .endDate(endDateTime)
                .totalWarnings(totalWarnings)
                .pendingWarnings(pendingWarnings)
                .resolvedWarnings(resolvedWarnings)
                .ignoredWarnings(ignoredWarnings)
                .criticalWarnings(criticalWarnings)
                .warningWarnings(warningWarnings)
                .infoWarnings(infoWarnings)
                .lowStockWarnings(lowStockWarnings)
                .highStockWarnings(highStockWarnings)
                .outOfStockWarnings(outOfStockWarnings)
                .resolveRate(Math.round(resolveRate * 100) / 100.0)
                .avgResolveTimeMinutes(Math.round(avgResolveTimeMinutes * 100) / 100.0)
                .build();
    }

    // ==================== 预警通知配置 ====================

    @Override
    @Transactional
    public StockWarningRule updateNotificationConfig(WarningNotificationConfigRequest request) {
        StockWarningRule rule = warningRuleRepository.selectById(request.getRuleId());
        if (rule == null) {
            throw new RuntimeException("预警规则不存在");
        }

        if (request.getNotificationMethods() != null) {
            rule.setNotificationMethods(request.getNotificationMethods());
        }
        if (request.getNotificationEmails() != null) {
            rule.setNotificationEmails(request.getNotificationEmails());
        }
        if (request.getDingtalkWebhook() != null) {
            rule.setDingtalkWebhook(request.getDingtalkWebhook());
        }
        if (request.getDingtalkSecret() != null) {
            rule.setDingtalkSecret(request.getDingtalkSecret());
        }
        if (request.getRepeatIntervalMinutes() != null) {
            rule.setRepeatIntervalMinutes(request.getRepeatIntervalMinutes());
        }

        warningRuleRepository.updateById(rule);
        log.info("更新预警通知配置: ruleId={}", request.getRuleId());
        return rule;
    }

    @Override
    public void testNotification(Long ruleId, String method) {
        StockWarningRule rule = warningRuleRepository.selectById(ruleId);
        if (rule == null) {
            throw new RuntimeException("预警规则不存在");
        }

        // 创建测试预警记录
        StockWarningRecord testRecord = StockWarningRecord.builder()
                .ruleId(rule.getId())
                .ruleName(rule.getRuleName() + " - 测试")
                .ruleType(rule.getRuleType())
                .skuCode("TEST_SKU")
                .skuName("测试商品")
                .warehouseId(rule.getWarehouseId())
                .warehouseName(rule.getWarehouseName())
                .currentQuantity(10)
                .availableQuantity(10)
                .warningThreshold(rule.getWarningThreshold())
                .deficit(5)
                .level(StockWarningRecord.Level.INFO.getCode())
                .message("这是一条测试预警消息")
                .status(StockWarningRecord.Status.PENDING.getCode())
                .notificationMethod(method)
                .build();

        boolean success = switch (method) {
            case "system" -> notificationService.sendSystemNotification(testRecord, rule);
            case "email" -> notificationService.sendEmailNotification(testRecord, rule);
            case "dingtalk" -> notificationService.sendDingTalkNotification(testRecord, rule);
            default -> throw new IllegalArgumentException("未知的通知方式: " + method);
        };

        if (!success) {
            throw new RuntimeException("测试通知发送失败");
        }
    }

    // ==================== DTO转换方法 ====================

    private StockWarningRuleDTO toRuleDTO(StockWarningRule rule) {
        StockWarningRule.RuleType ruleType = StockWarningRule.RuleType.fromCode(rule.getRuleType());
        String enabledLabel = rule.getEnabled() != null && rule.getEnabled() == 1 ? "启用" : "禁用";

        // 解析通知方式标签
        String notificationMethodsLabel = "";
        if (rule.getNotificationMethods() != null && !rule.getNotificationMethods().isEmpty()) {
            notificationMethodsLabel = Arrays.stream(rule.getNotificationMethods().split(","))
                    .map(m -> {
                        StockWarningRule.NotificationMethod method =
                                StockWarningRule.NotificationMethod.fromCode(m.trim());
                        return method != null ? method.getLabel() : m.trim();
                    })
                    .collect(Collectors.joining(", "));
        }

        return StockWarningRuleDTO.builder()
                .id(rule.getId())
                .ruleName(rule.getRuleName())
                .ruleType(rule.getRuleType())
                .ruleTypeLabel(ruleType != null ? ruleType.getLabel() : rule.getRuleType())
                .skuCode(rule.getSkuCode())
                .skuName(rule.getSkuName())
                .warehouseId(rule.getWarehouseId())
                .warehouseName(rule.getWarehouseName())
                .safetyStockMin(rule.getSafetyStockMin())
                .safetyStockMax(rule.getSafetyStockMax())
                .warningThreshold(rule.getWarningThreshold())
                .maxStockThreshold(rule.getMaxStockThreshold())
                .enabled(rule.getEnabled())
                .enabledLabel(enabledLabel)
                .notificationMethods(rule.getNotificationMethods())
                .notificationMethodsLabel(notificationMethodsLabel)
                .notificationEmails(rule.getNotificationEmails())
                .dingtalkWebhook(rule.getDingtalkWebhook())
                .repeatIntervalMinutes(rule.getRepeatIntervalMinutes())
                .remark(rule.getRemark())
                .createdAt(rule.getCreatedAt())
                .updatedAt(rule.getUpdatedAt())
                .createdByName(rule.getCreatedByName())
                .build();
    }

    private StockWarningRecordDTO toRecordDTO(StockWarningRecord record) {
        StockWarningRule.RuleType ruleType = StockWarningRule.RuleType.fromCode(record.getRuleType());
        StockWarningRecord.Level level = StockWarningRecord.Level.fromCode(record.getLevel());
        StockWarningRecord.Status status = StockWarningRecord.Status.fromCode(record.getStatus());

        Long durationMinutes = null;
        if (record.getCreatedAt() != null) {
            LocalDateTime endTime = record.getResolvedAt() != null ? record.getResolvedAt() : LocalDateTime.now();
            durationMinutes = ChronoUnit.MINUTES.between(record.getCreatedAt(), endTime);
        }

        return StockWarningRecordDTO.builder()
                .id(record.getId())
                .ruleId(record.getRuleId())
                .ruleName(record.getRuleName())
                .ruleType(record.getRuleType())
                .ruleTypeLabel(ruleType != null ? ruleType.getLabel() : record.getRuleType())
                .skuCode(record.getSkuCode())
                .skuName(record.getSkuName())
                .warehouseId(record.getWarehouseId())
                .warehouseName(record.getWarehouseName())
                .currentQuantity(record.getCurrentQuantity())
                .availableQuantity(record.getAvailableQuantity())
                .warningThreshold(record.getWarningThreshold())
                .deficit(record.getDeficit())
                .level(record.getLevel())
                .levelLabel(level != null ? level.getLabel() : record.getLevel())
                .message(record.getMessage())
                .status(record.getStatus())
                .statusLabel(status != null ? status.getLabel() : record.getStatus())
                .notificationMethod(record.getNotificationMethod())
                .notificationSuccess(record.getNotificationSuccess())
                .notificationError(record.getNotificationError())
                .acknowledgedAt(record.getAcknowledgedAt())
                .acknowledgedByName(record.getAcknowledgedByName())
                .resolvedAt(record.getResolvedAt())
                .resolvedRemark(record.getResolvedRemark())
                .createdAt(record.getCreatedAt())
                .durationMinutes(durationMinutes)
                .build();
    }
}
