package com.zksy.dispatch.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zksy.dispatch.domain.DisEventRecord;
import com.zksy.dispatch.dto.DisEventRecordPageDTO;
import com.zksy.dispatch.dto.EventStatsVO;
import com.zksy.dispatch.mapper.DisEventRecordMapper;
import com.zksy.dispatch.service.DisEventRecordService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;

/**
 * 应急事件数据记录 Service 实现（数据查询与统计）
 */
@Slf4j
@Service
public class DisEventRecordServiceImpl extends ServiceImpl<DisEventRecordMapper, DisEventRecord>
        implements DisEventRecordService {

    @Override
    public Page<DisEventRecord> findByPage(DisEventRecordPageDTO dto) {
        Page<DisEventRecord> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        return this.page(page, buildWrapper(dto));
    }

    @Override
    public EventStatsVO stats(DisEventRecordPageDTO dto) {
        List<DisEventRecord> records = this.list(buildWrapper(dto));
        EventStatsVO vo = new EventStatsVO();
        vo.setTotalEvents((long) records.size());
        BigDecimal totalLoss = records.stream()
                .map(DisEventRecord::getLossAmount)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        vo.setTotalLoss(totalLoss);
        vo.setAvgLoss(records.isEmpty() ? BigDecimal.ZERO
                : totalLoss.divide(BigDecimal.valueOf(records.size()), 1, RoundingMode.HALF_UP));
        long majorEvents = records.stream()
                .filter(r -> "重大".equals(r.getEventLevel()) || "特别重大".equals(r.getEventLevel()))
                .count();
        vo.setMajorEvents(majorEvents);
        return vo;
    }

    /**
     * 构建多维条件查询条件（与页面筛选逻辑一致）
     */
    private LambdaQueryWrapper<DisEventRecord> buildWrapper(DisEventRecordPageDTO dto) {
        LambdaQueryWrapper<DisEventRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.isNotEmpty(dto.getEventName()), DisEventRecord::getEventName, dto.getEventName());
        wrapper.eq(StringUtils.isNotEmpty(dto.getEventType()), DisEventRecord::getEventType, dto.getEventType());
        if (StringUtils.isNotEmpty(dto.getEventTime())) {
            try {
                wrapper.eq(DisEventRecord::getEventTime, LocalDate.parse(dto.getEventTime()));
            } catch (Exception e) {
                log.warn("事件时间格式错误: {}", dto.getEventTime());
            }
        }
        wrapper.eq(StringUtils.isNotEmpty(dto.getEventLevel()), DisEventRecord::getEventLevel, dto.getEventLevel());
        wrapper.eq(StringUtils.isNotEmpty(dto.getRegion()), DisEventRecord::getRegion, dto.getRegion());
        wrapper.eq(StringUtils.isNotEmpty(dto.getDepartment()), DisEventRecord::getDepartment, dto.getDepartment());
        applyLossRange(wrapper, dto.getLossRange());
        wrapper.orderByDesc(DisEventRecord::getEventTime);
        return wrapper;
    }

    /**
     * 损失情况区间条件
     */
    private void applyLossRange(LambdaQueryWrapper<DisEventRecord> wrapper, String lossRange) {
        if (StringUtils.isEmpty(lossRange)) {
            return;
        }
        switch (lossRange) {
            case "100万以下":
                wrapper.lt(DisEventRecord::getLossAmount, new BigDecimal(100));
                break;
            case "100-500万":
                wrapper.ge(DisEventRecord::getLossAmount, new BigDecimal(100))
                        .lt(DisEventRecord::getLossAmount, new BigDecimal(500));
                break;
            case "500-1000万":
                wrapper.ge(DisEventRecord::getLossAmount, new BigDecimal(500))
                        .lt(DisEventRecord::getLossAmount, new BigDecimal(1000));
                break;
            case "1000万以上":
                wrapper.ge(DisEventRecord::getLossAmount, new BigDecimal(1000));
                break;
            default:
                break;
        }
    }
}
