package com.hdkj.lt.bf.controller.optimization;

import com.alibaba.fastjson.JSON;
import com.hdkj.fhzg.optimization.request.MaintOrgRequest;
import com.hdkj.hussar.ApiResponse;
import com.hdkj.lt.bf.adapter.SiStateEstimationClient;
import com.hdkj.lt.bf.common.SeSnapshotConstants;
import com.hdkj.lt.bf.entity.dto.SeOverloadAlarmListReq;
import com.hdkj.lt.bf.entity.dto.SeVoltageAlarmListReq;
import com.hdkj.lt.bf.entity.vo.PageResult;
import com.hdkj.lt.bf.entity.vo.SeCapacityDashboardVO;
import com.hdkj.lt.bf.entity.vo.FeederSelectVO;
import com.hdkj.lt.bf.entity.vo.SeAlarmDetailVO;
import com.hdkj.lt.bf.entity.vo.SeAlarmListVO;
import com.hdkj.lt.bf.entity.vo.SeOutageDashboardVO;
import com.hdkj.lt.bf.entity.vo.SeVoltageDashboardVO;
import com.hdkj.lt.bf.scheduler.SeCapacityDailyScheduler;
import com.hdkj.lt.bf.service.SeAlarmService;
import com.hdkj.lt.bf.service.SeIndicatorService;
import com.hdkj.lt.bf.service.SeSnapshotService;
import com.hdkj.lt.core.bizms.modle.dto.StateEstimation;
import com.hdkj.lt.core.mvc.BaseController;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

/**
 * 运行态指标 Controller
 * <p>
 * 三个独立接口：/indicator/outage、/indicator/voltage、/indicator/capacity
 *
 * @author lsl
 * @since 2026-07-21
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/indicator")
public class IndicatorController extends BaseController {

    private final SeIndicatorService seIndicatorService;
    private final SeAlarmService seAlarmService;
    private final SiStateEstimationClient siStateEstimationClient;
    private final SeSnapshotService seSnapshotService;
    private final SeCapacityDailyScheduler seCapacityDailyScheduler;

    /**
     * 停电时户数（无时间维度切换）
     *
     * @param params {id, type(2/3/4)}
     */
    @PostMapping("/outage")
    public ApiResponse<SeOutageDashboardVO> outage(@RequestBody Map<String, String> params) {
        String id = params.get("id");
        String type = params.get("type");
        if (id == null || type == null) {
            return ApiResponse.fail("参数缺失");
        }
        return ApiResponse.success(seIndicatorService.queryOutage(id, Integer.parseInt(type)));
    }

    /**
     * 电压质量（today/month/year）
     *
     * @param params {id, type(2/3/4), timeScope(today/month/year)}
     */
    @PostMapping("/voltage")
    public ApiResponse<SeVoltageDashboardVO> voltage(@RequestBody Map<String, String> params) {
        String id = params.get("id");
        String type = params.get("type");
        String timeScope = params.get("timeScope");
        if (id == null || type == null || timeScope == null) {
            return ApiResponse.fail("参数缺失");
        }
        return ApiResponse.success(seIndicatorService.queryVoltage(id, Integer.parseInt(type), timeScope));
    }

    /**
     * 供电能力（today/month/year）
     *
     * @param params {id, type(2/3/4), timeScope(today/month/year)}
     */
    @PostMapping("/capacity")
    public ApiResponse<SeCapacityDashboardVO> capacity(@RequestBody Map<String, String> params) {
        String id = params.get("id");
        String type = params.get("type");
        String timeScope = params.get("timeScope");
        if (id == null || type == null || timeScope == null) {
            return ApiResponse.fail("参数缺失");
        }
        return ApiResponse.success(seIndicatorService.queryCapacity(id, Integer.parseInt(type), timeScope));
    }

    /**
     * 异常告警-线路重过载列表
     */
    @PostMapping("/alarm/overload")
    public ApiResponse<PageResult<SeAlarmListVO>> alarmOverload(@RequestBody SeOverloadAlarmListReq req) {
        if (req.getId() == null || req.getType() == null) {
            return ApiResponse.fail("参数缺失");
        }
        return ApiResponse.success(seAlarmService.queryOverloadAlarmList(req));
    }

    /**
     * 异常告警-电压越限列表
     */
    @PostMapping("/alarm/voltage")
    public ApiResponse<PageResult<SeAlarmListVO>> alarmVoltage(@RequestBody SeVoltageAlarmListReq req) {
        if (req.getId() == null || req.getType() == null) {
            return ApiResponse.fail("参数缺失");
        }
        return ApiResponse.success(seAlarmService.queryVoltageAlarmList(req));
    }

    /**
     * 运行异常信息详情
     * <p>
     * 两种查询方式：
     * - 传 alarmEventId -> 查重过载事件（老逻辑兼容）
     * - 传 feederId + firstOverTime -> 查电压越限详情
     *
     * @param params {alarmEventId} 或 {feederId, firstOverTime}
     */
    @PostMapping("/alarm/detail")
    public ApiResponse<SeAlarmDetailVO> alarmDetail(@RequestBody Map<String, String> params) {
        String alarmEventId = params.get("alarmEventId");
        if (alarmEventId == null || alarmEventId.isEmpty()) {
            return ApiResponse.fail("参数缺失");
        }
        return ApiResponse.success(seAlarmService.queryAlarmDetail(Long.parseLong(alarmEventId)));
    }

    /**
     * 线路名称下拉列表
     *
     * @param params {id, type(2/3/4)}
     */
    @PostMapping("/alarm/feederList")
    public ApiResponse<java.util.List<FeederSelectVO>> feederList(@RequestBody Map<String, String> params) {
        String id = params.get("id");
        String type = params.get("type");
        if (id == null || type == null) {
            return ApiResponse.fail("参数缺失");
        }
        return ApiResponse.success(seAlarmService.queryFeederList(id, Integer.parseInt(type)));
    }

    /**
     * 手动触发状估断面拉取
     * <p>
     * 按县域调 SI queryEquipByCounty 拉取状估数据，聚合后送入 processSnapshot 解析。
     * 传 snapTime 时启用覆盖更新：先删该断面时刻存量明细再重新写入。
     * 传 pointTime 时按指定历史时刻拉取（SI 侧优先使用该时刻），不传则拉当前最新。
     *
     * @param params {snapTime(可选, yyyy-MM-dd HH:mm:ss)，传值时覆盖更新; pointTime(可选, yyyy-MM-dd HH:mm:ss)，指定拉取时刻}
     */
    @PostMapping("/snapshot/manual")
    public ApiResponse<String> manualSnapshot(@RequestBody Map<String, String> params) {
        String snapTimeStr = params.get("snapTime");
        String pointTime = params.get("pointTime");
        // 传 snapTime 或 pointTime 均走覆盖更新：手动补断面就是要重写该时刻存量
        boolean overwrite = StringUtils.isNotBlank(snapTimeStr) || StringUtils.isNotBlank(pointTime);

        log.info("手动状估拉取开始 overwrite={}, pointTime={}", overwrite, pointTime);
        int successCount = 0;
        List<String> errors = new ArrayList<>();

        for (Map.Entry<String, String[]> county : SeSnapshotConstants.COUNTIES) {
            String maintOrg = county.getKey();
            String countyName = county.getValue()[1];
            try {
                MaintOrgRequest request = new MaintOrgRequest();
                request.setMaintOrg(maintOrg);
                if (StringUtils.isNotBlank(pointTime)) {
                    request.setPointTime(pointTime);
                }

                ApiResponse<List<StateEstimation>> resp = siStateEstimationClient.queryEquipByCounty(request);
                if (resp == null || !resp.isSuccess() || resp.getData() == null || resp.getData().isEmpty()) {
                    errors.add(countyName + "无数据");
                    log.warn("手动状估拉取 县域{} 无数据, resp={}", countyName, resp != null ? resp.isSuccess() : "null");
                    continue;
                }

                StateEstimation merged = mergeCountyResults(resp.getData());
                if (merged == null) {
                    errors.add(countyName + "聚合后无数据");
                    continue;
                }

                String json = JSON.toJSONString(merged);
                if (overwrite) {
                    seSnapshotService.processSnapshotOverwrite(json);
                } else {
                    seSnapshotService.processSnapshot(json);
                }
                successCount++;
                log.info("手动状估拉取完成 county={}, pointTime={}", countyName, merged.getPointTime());
            } catch (Exception e) {
                log.error("手动状估拉取异常 county={}", countyName, e);
                errors.add(countyName + "异常:" + e.getMessage());
            }
        }

        StringBuilder msg = new StringBuilder();
        msg.append("成功处理").append(successCount).append("个县域");
        if (!errors.isEmpty()) {
            msg.append("，").append(errors.size()).append("个异常：").append(String.join("; ", errors));
        }
        return ApiResponse.success(msg.toString());
    }

    /**
     * 手动触发供电能力日汇总刷数
     * <p>
     * 默认重跑今天的数据（覆盖更新：先删再插）。传 statDate 时重跑指定日期。
     *
     * @param params {statDate(可选, yyyy-MM-dd)，默认当天}
     */
    @PostMapping("/capacity/manual")
    public ApiResponse<String> manualCapacityDaily(@RequestBody Map<String, String> params) {
        String statDateStr = params.get("statDate");
        LocalDate date;
        if (StringUtils.isNotBlank(statDateStr)) {
            try {
                date = LocalDate.parse(statDateStr);
            } catch (Exception e) {
                return ApiResponse.fail("日期格式非法，期望 yyyy-MM-dd");
            }
        } else {
            date = LocalDate.now();
        }

        log.info("[供电能力日汇总] 手动触发刷数 statDate={}", date);
        try {
            String result = seCapacityDailyScheduler.aggregateForDate(date);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("[供电能力日汇总] 手动触发异常", e);
            return ApiResponse.fail("执行异常: " + e.getMessage());
        }
    }

    private StateEstimation mergeCountyResults(List<StateEstimation> list) {
        if (list == null || list.isEmpty()) return null;

        StateEstimation merged = new StateEstimation();
        List<StateEstimation.StateEstimationCommonResult> allFeeders = new ArrayList<>();
        List<StateEstimation.StateEstimationTransResult> allMvtrans = new ArrayList<>();
        List<StateEstimation.StateEstimationSwitchResult> allSwitches = new ArrayList<>();
        List<StateEstimation.StateEstimationCommonResult> allEquips = new ArrayList<>();
        List<StateEstimation.StateEstimationSegmentResult> allSegments = new ArrayList<>();
        List<String> pointTime = null;

        for (StateEstimation se : list) {
            if (se == null) continue;
            if (pointTime == null && se.getPointTime() != null) pointTime = se.getPointTime();
            if (se.getPeriodFeederSeResult() != null) allFeeders.addAll(se.getPeriodFeederSeResult());
            if (se.getPeriodMVTransSeResult() != null) allMvtrans.addAll(se.getPeriodMVTransSeResult());
            if (se.getPeriodSwitchSeResult() != null) allSwitches.addAll(se.getPeriodSwitchSeResult());
            if (se.getPeriodEquipResult() != null) allEquips.addAll(se.getPeriodEquipResult());
            if (se.getPeriodSegmentSeResult() != null) allSegments.addAll(se.getPeriodSegmentSeResult());
        }

        if (allFeeders.isEmpty() && allMvtrans.isEmpty()) {
            log.warn("手动状估拉取 聚合后无任何数据");
            return null;
        }

        merged.setPeriodFeederSeResult(allFeeders);
        merged.setPeriodMVTransSeResult(allMvtrans);
        merged.setPeriodSwitchSeResult(allSwitches);
        merged.setPeriodEquipResult(allEquips);
        merged.setPeriodSegmentSeResult(allSegments);
        merged.setPointTime(pointTime);
        return merged;
    }
}
