package com.zksy.base.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zksy.base.constant.GasEquipmentTypeEnum;
import com.zksy.base.domain.EquipmentBase;
import com.zksy.base.domain.EquipmentType;
import com.zksy.base.domain.TerminalFault;
import com.zksy.base.mapper.EquipmentBaseMapper;
import com.zksy.base.mapper.EquipmentTypeMapper;
import com.zksy.base.mapper.TerminalFaultMapper;
import com.zksy.base.service.EquipmentAbnormalService;
import com.zksy.common.utils.StringUtils;
import com.zksy.manhole.dto.out.TerminalFaultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class EquipmentAbnormalServiceImpl implements EquipmentAbnormalService {

    @Autowired
    private TerminalFaultMapper terminalFaultMapper;
    @Autowired
    private EquipmentBaseMapper equipmentBaseMapper;
    @Autowired
    private EquipmentTypeMapper equipmentTypeMapper;

    /** 燃气顶级类型 parent_type_id */
    private static final String GAS_PARENT_TYPE_ID = GasEquipmentTypeEnum.PARENT_TYPE_ID;

    // 故障等级文本
    private static final Map<Integer, String> LEVEL_MAP = new HashMap<>();
    static {
        LEVEL_MAP.put(1, "严重");
        LEVEL_MAP.put(2, "一般");
        LEVEL_MAP.put(3, "轻微");
    }

    // 故障状态文本
    private static final Map<Integer, String> STATUS_MAP = new HashMap<>();
    static {
        STATUS_MAP.put(1, "待处理");
        STATUS_MAP.put(2, "处理中");
        STATUS_MAP.put(3, "已修复");
        STATUS_MAP.put(4, "已返厂");
        STATUS_MAP.put(5, "已报废");
    }

    @Override
    public Map<String, Object> getList(int pageNum, int pageSize, String searchKey, String level, String type, String status) {
        // 1. 先查出所有燃气设备(equipment_type_id以GAS-开头)
        List<EquipmentType> gasTypes = equipmentTypeMapper.selectList(
                new LambdaQueryWrapper<EquipmentType>()
                        .eq(EquipmentType::getParentTypeId, GAS_PARENT_TYPE_ID)
        );
        if (gasTypes.isEmpty()) {
            Map<String, Object> emptyResult = new LinkedHashMap<>();
            emptyResult.put("total", 0L);
            emptyResult.put("rows", new ArrayList<>());
            return emptyResult;
        }
        Set<String> gasTypeIds = gasTypes.stream().map(EquipmentType::getId).collect(Collectors.toSet());

        List<EquipmentBase> gasEquipments = equipmentBaseMapper.selectList(
                new LambdaQueryWrapper<EquipmentBase>()
                        .in(EquipmentBase::getEquipmentTypeId, gasTypeIds)
        );
        if (gasEquipments.isEmpty()) {
            Map<String, Object> emptyResult = new LinkedHashMap<>();
            emptyResult.put("total", 0L);
            emptyResult.put("rows", new ArrayList<>());
            return emptyResult;
        }
        Set<String> gasEquipmentIds = gasEquipments.stream().map(EquipmentBase::getEquipmentId).collect(Collectors.toSet());
        Map<String, EquipmentBase> equipmentMap = gasEquipments.stream()
                .collect(Collectors.toMap(EquipmentBase::getEquipmentId, e -> e, (a, b) -> a));

        // 类型ID → 类型名称
        Map<String, String> typeNameMap = gasTypes.stream()
                .collect(Collectors.toMap(EquipmentType::getId, EquipmentType::getTypeName, (a, b) -> a));

        // 2. 查询terminal_fault，过滤燃气设备
        LambdaQueryWrapper<TerminalFault> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(TerminalFault::getDeviceId, gasEquipmentIds);

        // 筛选条件
        if (StringUtils.isNotEmpty(searchKey)) {
            queryWrapper.and(w -> w.like(TerminalFault::getDeviceCode, searchKey)
                    .or().like(TerminalFault::getFaultDesc, searchKey));
        }
        if (StringUtils.isNotEmpty(level)) {
            Integer lv = parseLevel(level);
            if (lv != null) queryWrapper.eq(TerminalFault::getFaultLevel, lv);
        }
        if (StringUtils.isNotEmpty(status)) {
            Integer st = parseStatus(status);
            if (st != null) queryWrapper.eq(TerminalFault::getFaultStatus, st);
        }
        queryWrapper.orderByDesc(TerminalFault::getUpdateTime);

        // 3. 分页
        long total = terminalFaultMapper.selectCount(queryWrapper);
        int offset = (pageNum - 1) * pageSize;
        List<TerminalFault> faults = terminalFaultMapper.selectList(
                queryWrapper.last("limit " + offset + ", " + pageSize)
        );

        // 4. 组装VO + 设备类型筛选
        List<TerminalFaultVO> rows = new ArrayList<>();
        for (int i = 0; i < faults.size(); i++) {
            TerminalFault f = faults.get(i);
            EquipmentBase eq = equipmentMap.get(f.getDeviceId());
            TerminalFaultVO vo = new TerminalFaultVO();
            vo.setFaultId(f.getFaultId());
            vo.setFaultNo(f.getFaultNo());
            vo.setDeviceId(f.getDeviceId());
            vo.setDeviceCode(f.getDeviceCode());
            vo.setDeviceName(eq != null ? eq.getEquipmentName() : f.getDeviceCode());
            vo.setDeviceType(eq != null ? typeNameMap.getOrDefault(eq.getEquipmentTypeId(), "未知") : "未知");
            vo.setAddress(eq != null ? eq.getEquipmentLocation() : "");
            vo.setFaultLevel(f.getFaultLevel());
            vo.setLevelText(LEVEL_MAP.getOrDefault(f.getFaultLevel(), "未知"));
            vo.setAlarmDesc(f.getFaultDesc());
            vo.setFaultSource(f.getFaultSource());
            vo.setFaultStatus(f.getFaultStatus());
            vo.setProcessStatus(STATUS_MAP.getOrDefault(f.getFaultStatus(), "未知"));
            vo.setAlarmTime(f.getHappenTime());
            rows.add(vo);
        }

        // 设备类型筛选(在内存中做，因为类型名称需要join后才能得到)
        if (StringUtils.isNotEmpty(type)) {
            rows = rows.stream().filter(r -> type.equals(r.getDeviceType())).collect(Collectors.toList());
        }

        Map<String, Object> result = new LinkedHashMap<>();
        result.put("total", total);
        result.put("rows", rows);
        return result;
    }

    @Override
    public Map<String, Object> getStats() {
        // 燃气设备总故障统计
        List<EquipmentType> gasTypes = equipmentTypeMapper.selectList(
                new LambdaQueryWrapper<EquipmentType>().eq(EquipmentType::getParentTypeId, GAS_PARENT_TYPE_ID)
        );
        if (gasTypes.isEmpty()) {
            return buildEmptyStats();
        }
        Set<String> gasTypeIds = gasTypes.stream().map(EquipmentType::getId).collect(Collectors.toSet());
        List<EquipmentBase> gasEquipments = equipmentBaseMapper.selectList(
                new LambdaQueryWrapper<EquipmentBase>().in(EquipmentBase::getEquipmentTypeId, gasTypeIds)
        );
        if (gasEquipments.isEmpty()) {
            return buildEmptyStats();
        }
        Set<String> gasEquipmentIds = gasEquipments.stream().map(EquipmentBase::getEquipmentId).collect(Collectors.toSet());
        Map<String, String> typeNameMap = gasTypes.stream()
                .collect(Collectors.toMap(EquipmentType::getId, EquipmentType::getTypeName, (a, b) -> a));

        List<TerminalFault> allFaults;
        if (!gasEquipmentIds.isEmpty()) {
            allFaults = terminalFaultMapper.selectList(
                    new LambdaQueryWrapper<TerminalFault>().in(TerminalFault::getDeviceId, gasEquipmentIds)
            );
        } else {
            allFaults = new ArrayList<>();
        }

        // ---- 日期范围: 前15天 ----
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        LocalDate today = LocalDate.now();
        LocalDate rangeStart = today.minusDays(14);
        String todayStr = today.toString();

        // 前15天内发生的故障
        List<TerminalFault> recentFaults = allFaults.stream()
                .filter(f -> f.getHappenTime() != null)
                .filter(f -> {
                    LocalDate hd = f.getHappenTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                    return !hd.isBefore(rangeStart) && !hd.isAfter(today);
                })
                .collect(Collectors.toList());

        int totalFaults = allFaults.size();
        int recentFaultCount = recentFaults.size();
        long totalDevices = recentFaults.stream().map(TerminalFault::getDeviceId).filter(Objects::nonNull).distinct().count();

        // 今日新增 = happen_time为今天(去重设备数) 一天有可能同一个设备上报多个故障
        long todayCount = allFaults.stream()
                .filter(f -> f.getHappenTime() != null && sdf.format(f.getHappenTime()).equals(todayStr))
                .map(TerminalFault::getDeviceId).filter(Objects::nonNull).distinct().count();

        int critical = (int) recentFaults.stream().filter(f -> f.getFaultLevel() != null && f.getFaultLevel() == 1).count();
        int normalLv = (int) recentFaults.stream().filter(f -> f.getFaultLevel() != null && f.getFaultLevel() == 2).count();
        int minor = (int) recentFaults.stream().filter(f -> f.getFaultLevel() != null && f.getFaultLevel() == 3).count();

        // 已修复: 前15天内故障中 faultStatus==3 的数量
        int processed = (int) recentFaults.stream().filter(f -> f.getFaultStatus() != null && f.getFaultStatus() == 3).count();
        // 待处理: 前15天内故障中 faultStatus==1 的数量
        int pending = (int) recentFaults.stream().filter(f -> f.getFaultStatus() != null && f.getFaultStatus() == 1).count();

        int totalEquipment = gasEquipments.size();
        // 异常占比 = 前15天异常设备数 / 燃气设备总数 × 100
        double rate = totalEquipment > 0 ? Math.round(totalDevices * 100.0 / totalEquipment * 10) / 10.0 : 0;
        // 修复率 = 前15天已修复数 / 前15天故障总数 × 100
        double processRate = recentFaultCount > 0 ? Math.round(processed * 100.0 / recentFaultCount * 10) / 10.0 : 0;

        // 按设备类型统计(前15天故障记录数)
        Map<String, Integer> typeCountMap = new LinkedHashMap<>();
        for (TerminalFault f : recentFaults) {
            EquipmentBase eq = gasEquipments.stream()
                    .filter(e -> e.getEquipmentId().equals(f.getDeviceId()))
                    .findFirst().orElse(null);
            String typeName = eq != null ? typeNameMap.getOrDefault(eq.getEquipmentTypeId(), "其他") : "其他";
            typeCountMap.merge(typeName, 1, Integer::sum);
        }

        // ---- 近15天趋势 ----
        // totalData = 累计未修复数 = 前一天total + 当天新增 - 当天修复
        DateTimeFormatter dateFmt = DateTimeFormatter.ofPattern("MM-dd");

        // 预计算每天的new和fixed数量
        Map<String, Integer> newByDay = new LinkedHashMap<>();
        Map<String, Integer> fixedByDay = new LinkedHashMap<>();
        for (TerminalFault f : allFaults) {
            if (f.getHappenTime() != null) {
                newByDay.merge(sdf.format(f.getHappenTime()), 1, Integer::sum);
            }
            if (f.getHandleTime() != null) {
                fixedByDay.merge(sdf.format(f.getHandleTime()), 1, Integer::sum);
            }
        }

        List<String> trendDates = new ArrayList<>();
        List<Integer> trendTotal = new ArrayList<>();
        List<Integer> trendNew = new ArrayList<>();
        List<Integer> trendFixed = new ArrayList<>();

        for (int d = 14; d >= 0; d--) {
            LocalDate day = today.minusDays(d);
            String dayStr = day.toString();
            trendDates.add(day.format(dateFmt));
            // 当天异常设备数 = happen_time为当天 且 fault_status未修复(1或2) 的去重设备数
            long totalByDay = allFaults.stream()
                    .filter(f -> f.getHappenTime() != null && sdf.format(f.getHappenTime()).equals(dayStr))
                    .map(TerminalFault::getDeviceId).filter(Objects::nonNull).distinct().count();
            int n = newByDay.getOrDefault(dayStr, 0);
            int f = fixedByDay.getOrDefault(dayStr, 0);
            trendTotal.add((int) totalByDay);
            trendNew.add(n);
            trendFixed.add(f);
        }

        // ---- 异常类型分布 (按fault_source) ----
        String[] sourceLabels = {"设备报警", "人工上报", "巡检发现"};
        int[] sourceValues = new int[3];
        for (TerminalFault f : allFaults) {
            if (f.getFaultSource() != null && f.getFaultSource() >= 1 && f.getFaultSource() <= 3) {
                sourceValues[f.getFaultSource() - 1]++;
            }
        }

        // ---- 等级×状态交叉统计 ----
        String[] levelLabels = {"严重", "一般", "轻微"};
        int[] pendingByLevel = new int[3];
        int[] processingByLevel = new int[3];
        int[] fixedByLevel = new int[3];
        for (TerminalFault f : allFaults) {
            int lv = f.getFaultLevel() != null ? f.getFaultLevel() : 2;
            if (lv < 1 || lv > 3) lv = 2;
            int idx = lv - 1;
            int st = f.getFaultStatus() != null ? f.getFaultStatus() : 1;
            if (st == 1) pendingByLevel[idx]++;
            else if (st == 2) processingByLevel[idx]++;
            else if (st == 3) fixedByLevel[idx]++;
        }

        Map<String, Object> result = new LinkedHashMap<>();
        result.put("total", (int) totalDevices);       // 异常设备数(去重)
        result.put("totalFaults", totalFaults);         // 故障记录总数
        result.put("today", todayCount);                // 今日新增
        result.put("rate", rate);                       // 异常占比(%)
        result.put("processed", processed);             // 已修复
        result.put("pending", pending);                 // 待处理
        result.put("processRate", processRate);         // 修复率(%)
        result.put("critical", critical);
        result.put("normal", normalLv);
        result.put("minor", minor);
        result.put("deviceTypeStats", typeCountMap);
        // 趋势
        Map<String, Object> trend = new LinkedHashMap<>();
        trend.put("dates", trendDates);
        trend.put("totalData", trendTotal);
        trend.put("newData", trendNew);
        trend.put("fixedData", trendFixed);
        result.put("trend", trend);
        // 类型分布
        Map<String, Object> typeDist = new LinkedHashMap<>();
        typeDist.put("categories", sourceLabels);
        typeDist.put("values", sourceValues);
        result.put("typeDistribution", typeDist);
        // 等级×状态
        Map<String, Object> levelStatus = new LinkedHashMap<>();
        levelStatus.put("levels", levelLabels);
        levelStatus.put("pending", pendingByLevel);
        levelStatus.put("processing", processingByLevel);
        levelStatus.put("fixed", fixedByLevel);
        result.put("levelStatus", levelStatus);
        return result;
    }

    private Map<String, Object> buildEmptyStats() {
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("total", 0);
        result.put("today", 0);
        result.put("rate", 0);
        result.put("processed", 0);
        result.put("pending", 0);
        result.put("processRate", 0);
        result.put("critical", 0);
        result.put("normal", 0);
        result.put("minor", 0);
        result.put("deviceTypeStats", new LinkedHashMap<>());
        result.put("trend", buildEmptyTrend());
        result.put("typeDistribution", buildEmptyTypeDist());
        result.put("levelStatus", buildEmptyLevelStatus());
        return result;
    }

    private Map<String, Object> buildEmptyTrend() {
        Map<String, Object> t = new LinkedHashMap<>();
        t.put("dates", new ArrayList<>());
        t.put("totalData", new ArrayList<>());
        t.put("newData", new ArrayList<>());
        t.put("fixedData", new ArrayList<>());
        return t;
    }

    private Map<String, Object> buildEmptyTypeDist() {
        Map<String, Object> d = new LinkedHashMap<>();
        d.put("categories", new String[]{"设备报警", "人工上报", "巡检发现"});
        d.put("values", new int[]{0, 0, 0});
        return d;
    }

    private Map<String, Object> buildEmptyLevelStatus() {
        Map<String, Object> ls = new LinkedHashMap<>();
        ls.put("levels", new String[]{"严重", "一般", "轻微"});
        ls.put("pending", new int[]{0, 0, 0});
        ls.put("processing", new int[]{0, 0, 0});
        ls.put("fixed", new int[]{0, 0, 0});
        return ls;
    }

    private Integer parseLevel(String level) {
        if ("严重".equals(level)) return 1;
        if ("一般".equals(level)) return 2;
        if ("轻微".equals(level)) return 3;
        return null;
    }

    private Integer parseStatus(String status) {
        if ("待处理".equals(status)) return 1;
        if ("处理中".equals(status)) return 2;
        if ("已修复".equals(status)) return 3;
        if ("已返厂".equals(status)) return 4;
        if ("已报废".equals(status)) return 5;
        return null;
    }
}
