package com.hdkj.lt.bf.scheduler;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hdkj.lt.bf.entity.FhzgSeConsumerCountDaily;
import com.hdkj.lt.bf.entity.FhzgSeConsumerRelation;
import com.hdkj.lt.bf.mapper.FhzgSeConsumerCountDailyMapper;
import com.hdkj.lt.bf.mapper.FhzgSeConsumerRelationMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 分层分级用户数量日汇总定时任务
 * <p>
 * 每天凌晨1点，从 fhzg_se_consumer_relation 按 county/substation/feeder 三档聚合，
 * 写入 fhzg_se_consumer_count_daily（IEC用户电压指数分母）。
 * 先删当天已有数据再插入（幂等）。
 *
 * @author lsl
 * @since 2026-07-30
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class SeConsumerCountDailyScheduler {

    private final FhzgSeConsumerRelationMapper consumerRelationMapper;
    private final FhzgSeConsumerCountDailyMapper consumerCountDailyMapper;

    /** 维度级别常量 */
    private static final String LEVEL_COUNTY = "county";
    private static final String LEVEL_SUBSTATION = "substation";
    private static final String LEVEL_FEEDER = "feeder";

    /**
     * 每天凌晨1点执行（刷昨天）
     */
    @Scheduled(cron = "0 0 1 * * ?")
    public void aggregateYesterdayConsumerCount() {
        LocalDate yesterday = LocalDate.now().minusDays(1);
        log.info("[用户数量日汇总] 开始处理 {} 数据", yesterday);
        try {
            String result = aggregateForDate(yesterday);
            log.info("[用户数量日汇总] {}", result);
        } catch (Exception e) {
            log.error("[用户数量日汇总] {} 处理失败", yesterday, e);
        }
    }

    /**
     * 聚合指定日期的分层分级用户数（手动触发时调用）
     * <p>
     * 三档独立聚合（SQL GROUP BY，不加载明细到内存）：
     * county 档 = county_id 非空按区县分组；
     * substation 档 = county_id+subs_id 非空按变电站分组；
     * feeder 档 = 三级id均非空按馈线分组。
     */
    public String aggregateForDate(LocalDate date) {
        List<FhzgSeConsumerCountDaily> records = new ArrayList<>();

        // 区县档
        records.addAll(aggregateLevel(date, LEVEL_COUNTY));

        // 变电站档
        records.addAll(aggregateLevel(date, LEVEL_SUBSTATION));

        // 馈线档
        records.addAll(aggregateLevel(date, LEVEL_FEEDER));

        if (records.isEmpty()) {
            log.info("[用户数量日汇总] {} 无用户关系数据，跳过", date);
            return date + " 无用户关系数据";
        }

        // 先删当天已有数据（幂等）
        LambdaQueryWrapper<FhzgSeConsumerCountDaily> deleteWrapper =
                new LambdaQueryWrapper<FhzgSeConsumerCountDaily>()
                        .eq(FhzgSeConsumerCountDaily::getStatDate, date);
        consumerCountDailyMapper.delete(deleteWrapper);

        // 批量插入
        for (FhzgSeConsumerCountDaily record : records) {
            consumerCountDailyMapper.insert(record);
        }

        String result = date + " 处理完成: " + records.size() + " 行 (county " + countByLevel(records, LEVEL_COUNTY)
                + " + substation " + countByLevel(records, LEVEL_SUBSTATION)
                + " + feeder " + countByLevel(records, LEVEL_FEEDER) + ")";
        log.info("[用户数量日汇总] {}", result);
        return result;
    }

    /**
     * 按指定维度档聚合用户数（一条 SQL GROUP BY）
     */
    private List<FhzgSeConsumerCountDaily> aggregateLevel(LocalDate date, String level) {
        QueryWrapper<FhzgSeConsumerRelation> qw = new QueryWrapper<>();
        qw.select("county_id", "subs_id", "feeder_id", "COUNT(*) AS cnt")
                .isNotNull("county_id")
                .groupBy("county_id");

        if (LEVEL_SUBSTATION.equals(level)) {
            qw.isNotNull("subs_id")
                    .groupBy("county_id", "subs_id");
        } else if (LEVEL_FEEDER.equals(level)) {
            qw.isNotNull("subs_id")
                    .isNotNull("feeder_id")
                    .groupBy("county_id", "subs_id", "feeder_id");
        }

        List<java.util.Map<String, Object>> rows = consumerRelationMapper.selectMaps(qw);

        List<FhzgSeConsumerCountDaily> records = new ArrayList<>();
        for (java.util.Map<String, Object> row : rows) {
            String countyId = (String) row.get("county_id");
            String subsId = (String) row.get("subs_id");
            String feederId = (String) row.get("feeder_id");
            Number cnt = (Number) row.getOrDefault("cnt", 0);

            records.add(FhzgSeConsumerCountDaily.builder()
                    .statDate(date)
                    .dimLevel(level)
                    .countyId(countyId)
                    .subsId(subsId)
                    .feederId(feederId)
                    .consumerCount(cnt.intValue())
                    .createTime(LocalDateTime.now())
                    .updateTime(LocalDateTime.now())
                    .build());
        }
        return records;
    }

    private long countByLevel(List<FhzgSeConsumerCountDaily> records, String level) {
        return records.stream().filter(r -> level.equals(r.getDimLevel())).count();
    }
}
