package com.aucma.production.service.impl;

import com.aucma.base.domain.BaseDeviceLedger;
import com.aucma.base.domain.BaseDeviceParamVal;
import com.aucma.base.mapper.BaseDeviceLedgerMapper;
import com.aucma.base.service.IDeviceParamReadFacade;
import com.aucma.base.service.IBaseDeviceParamValService;
import com.aucma.common.constant.AnDonConstants;
import com.aucma.common.utils.DateUtils;
import com.aucma.common.utils.StringUtils;
import com.aucma.production.domain.AndonEvent;
import com.aucma.production.domain.ProductPlanInfo;
import com.aucma.production.domain.ProductionReportQualityInspection;
import com.aucma.production.domain.dto.AndonDashboardDTO;
import com.aucma.production.mapper.AndonEventMapper;
import com.aucma.production.mapper.ProductPlanInfoMapper;
import com.aucma.production.mapper.ProductionReportQualityInspectionMapper;
import com.aucma.production.service.IAndonDashboardService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 安灯生产监控看板Service实现
 * 
 * @author Yinq
 * @date 2025-12-30
 */
@Service
public class AndonDashboardServiceImpl implements IAndonDashboardService {

    @Autowired
    private BaseDeviceLedgerMapper baseDeviceLedgerMapper;

    @Autowired
    private IDeviceParamReadFacade deviceParamReadFacade;

    @Autowired
    private IBaseDeviceParamValService baseDeviceParamValService;

    @Autowired
    private ProductPlanInfoMapper productPlanInfoMapper;

    @Autowired
    private AndonEventMapper andonEventMapper;

    @Autowired
    private ProductionReportQualityInspectionMapper reportQualityInspectionMapper;

    @Override
    public AndonDashboardDTO getDashboardData(String productLineCode) {
        AndonDashboardDTO dto = new AndonDashboardDTO();
        dto.setDeviceStatusSummary(getDeviceStatusSummary(productLineCode));
        dto.setTaskCompletionSummary(getTaskCompletionSummary(productLineCode));
        dto.setOeeSummary(getOeeSummary(productLineCode));
        dto.setUtilizationSummary(getUtilizationSummary(productLineCode));
        dto.setQualitySummary(getQualitySummary(productLineCode));
        dto.setAndonEventSummary(getAndonEventSummary(productLineCode));
        return dto;
    }

    @Override
    public AndonDashboardDTO.DeviceStatusSummary getDeviceStatusSummary(String productLineCode) {
        AndonDashboardDTO.DeviceStatusSummary summary = new AndonDashboardDTO.DeviceStatusSummary();
        
        // 为什么这样做：分表后状态查询依赖 tableSuffixes 路由，统一走 base 服务才能避免各调用方重复拼装参数。
        Map<String, Object> stats = baseDeviceParamValService.selectDeviceStatusStatistics();
        
        if (stats == null || stats.isEmpty()) {
            summary.setTotalDevices(0);
            summary.setRunningDevices(0);
            summary.setStoppedDevices(0);
            summary.setFaultDevices(0);
            summary.setIdleDevices(0);
            summary.setDeviceDetails(new ArrayList<>());
            return summary;
        }
        
        // 设置统计数据
        // 为什么这样做：不同 JDBC/MyBatis 映射下聚合别名可能保留原样，也可能被转成大写，这里同时兼容两种结果键。
        Number totalCount = getNumber(stats, "TOTALCOUNT", "totalCount");
        Number runningCount = getNumber(stats, "RUNNINGCOUNT", "runningCount");
        Number stoppedCount = getNumber(stats, "STOPPEDCOUNT", "stoppedCount");
        Number standbyCount = getNumber(stats, "STANDBYCOUNT", "standbyCount");
        Number alarmCount = getNumber(stats, "ALARMCOUNT", "alarmCount");
        
        summary.setTotalDevices(totalCount != null ? totalCount.intValue() : 0);
        summary.setRunningDevices(runningCount != null ? runningCount.intValue() : 0);
        summary.setStoppedDevices(stoppedCount != null ? stoppedCount.intValue() : 0);
        summary.setIdleDevices(standbyCount != null ? standbyCount.intValue() : 0);
        summary.setFaultDevices(alarmCount != null ? alarmCount.intValue() : 0);

        // 获取设备状态详情
        List<Map<String, Object>> deviceStatusList = baseDeviceParamValService.selectDeviceStatusList();
        List<AndonDashboardDTO.DeviceStatusDetail> details = new ArrayList<>();
        
        if (deviceStatusList != null) {
            for (Map<String, Object> device : deviceStatusList) {
                // 如果指定了产线编码，过滤设备
                if (StringUtils.isNotEmpty(productLineCode)) {
                    String lineCode = (String) device.get("productLineCode");
                    if (!productLineCode.equals(lineCode)) {
                        continue;
                    }
                }
                
                AndonDashboardDTO.DeviceStatusDetail detail = new AndonDashboardDTO.DeviceStatusDetail();
                detail.setDeviceCode((String) device.get("deviceCode"));
                detail.setDeviceName((String) device.get("deviceName"));
                detail.setProductLineCode((String) device.get("productLineCode"));
                detail.setProductLineName((String) device.get("productLineName"));
                
                Number statusCode = (Number) device.get("statusCode");
                detail.setStatus(statusCode != null ? statusCode.intValue() : 0);
                detail.setStatusName((String) device.get("deviceStatus"));
                details.add(detail);
            }
        }
        
        summary.setDeviceDetails(details);
        
        return summary;
    }

    @Override
    public AndonDashboardDTO.TaskCompletionSummary getTaskCompletionSummary(String productLineCode) {
        AndonDashboardDTO.TaskCompletionSummary summary = new AndonDashboardDTO.TaskCompletionSummary();
        
        // 获取今日日期范围
        Date todayStart = DateUtils.parseDate(DateUtils.getDate());
        Date todayEnd = DateUtils.addDays(todayStart, 1);
        
        // 获取本月日期范围
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        Date monthStart = cal.getTime();
        cal.add(Calendar.MONTH, 1);
        Date monthEnd = cal.getTime();

        // 查询生产计划
        ProductPlanInfo query = new ProductPlanInfo();
        query.setIsFlag(1L);
        if (StringUtils.isNotEmpty(productLineCode)) {
            query.setProductLineCode(productLineCode);
        }
        List<ProductPlanInfo> plans = productPlanInfoMapper.selectProductPlanInfoList(query);
        
        if (plans == null) plans = new ArrayList<>();

        // 今日统计
        long todayPlan = 0, todayComplete = 0;
        // 本月统计
        long monthPlan = 0, monthComplete = 0;
        // 按产线统计
        Map<String, long[]> lineStats = new HashMap<>(); // [plan, complete, lineName]
        Map<String, String> lineNames = new HashMap<>();

        for (ProductPlanInfo plan : plans) {
            Long planAmt = plan.getPlanAmount() == null ? 0L : plan.getPlanAmount();
            Long compAmt = plan.getCompleteAmount() == null ? 0L : plan.getCompleteAmount();
            Date planDate = plan.getPlanBeginTime();
            
            // 今日统计
            if (planDate != null && !planDate.before(todayStart) && planDate.before(todayEnd)) {
                todayPlan += planAmt;
                todayComplete += compAmt;
            }
            
            // 本月统计
            if (planDate != null && !planDate.before(monthStart) && planDate.before(monthEnd)) {
                monthPlan += planAmt;
                monthComplete += compAmt;
            }

            // 产线统计
            String lineCode = plan.getProductLineCode();
            if (StringUtils.isNotEmpty(lineCode)) {
                lineStats.computeIfAbsent(lineCode, k -> new long[2]);
                lineStats.get(lineCode)[0] += planAmt;
                lineStats.get(lineCode)[1] += compAmt;
                if (StringUtils.isNotEmpty(plan.getProductLineName())) {
                    lineNames.put(lineCode, plan.getProductLineName());
                }
            }
        }

        summary.setTodayPlanAmount(todayPlan);
        summary.setTodayCompleteAmount(todayComplete);
        summary.setTodayCompletionRate(calcRate(todayComplete, todayPlan));
        summary.setMonthPlanAmount(monthPlan);
        summary.setMonthCompleteAmount(monthComplete);
        summary.setMonthCompletionRate(calcRate(monthComplete, monthPlan));

        // 产线完成情况列表
        List<AndonDashboardDTO.LineTaskCompletion> lineCompletions = new ArrayList<>();
        for (Map.Entry<String, long[]> entry : lineStats.entrySet()) {
            AndonDashboardDTO.LineTaskCompletion lc = new AndonDashboardDTO.LineTaskCompletion();
            lc.setProductLineCode(entry.getKey());
            lc.setProductLineName(lineNames.getOrDefault(entry.getKey(), entry.getKey()));
            lc.setPlanAmount(entry.getValue()[0]);
            lc.setCompleteAmount(entry.getValue()[1]);
            lc.setCompletionRate(calcRate(entry.getValue()[1], entry.getValue()[0]));
            lineCompletions.add(lc);
        }
        summary.setLineCompletions(lineCompletions);

        return summary;
    }

    @Override
    public AndonDashboardDTO.OeeSummary getOeeSummary(String productLineCode) {
        AndonDashboardDTO.OeeSummary summary = new AndonDashboardDTO.OeeSummary();
        
        // 查询设备列表
        BaseDeviceLedger query = new BaseDeviceLedger();
        query.setIsFlag(1L);
        if (StringUtils.isNotEmpty(productLineCode)) {
            query.setProductLineCode(productLineCode);
        }
        List<BaseDeviceLedger> devices = baseDeviceLedgerMapper.selectBaseDeviceLedgerList(query);
        
        if (devices == null || devices.isEmpty()) {
            summary.setOverallOee(0);
            summary.setAvailability(0);
            summary.setPerformance(0);
            summary.setQuality(0);
            summary.setPlannedTimeMinutes(0);
            summary.setDowntimeMinutes(0);
            summary.setDeviceOeeDetails(new ArrayList<>());
            return summary;
        }

        List<AndonDashboardDTO.DeviceOeeDetail> details = new ArrayList<>();
        double totalAvailability = 0, totalPerformance = 0, totalQuality = 0;
        long totalPlannedTime = 0, totalDowntime = 0;

        for (BaseDeviceLedger device : devices) {
            // 为什么这样做：安灯是参数消费方，不应该继续直接注入明细 Mapper 感知底层单表/分表。
            double plannedTime = queryLatestDoubleValue(device.getDeviceCode(), "机台状态-总计划生产时间");
            double actualTime = queryLatestDoubleValue(device.getDeviceCode(), "机台状态-实际生产时间");
            long targetOutput = queryLatestLongValue(device.getDeviceCode(), "机台状态-设定产出数量");
            long actualOutput = queryLatestLongValue(device.getDeviceCode(), "机台状态-实际产出数量");
            
            // 计算OEE三个指标
            double availability = plannedTime > 0 ? (actualTime / plannedTime) : 0;
            double performance = targetOutput > 0 ? (actualOutput / targetOutput) : 0;
            double quality = 0.95;
            
            double oee = availability * performance * quality;
            
            totalPlannedTime += (long) plannedTime;
            totalDowntime += (long)(plannedTime - actualTime);
            totalAvailability += availability;
            totalPerformance += performance;
            totalQuality += quality;
            
            AndonDashboardDTO.DeviceOeeDetail detail = new AndonDashboardDTO.DeviceOeeDetail();
            detail.setDeviceCode(device.getDeviceCode());
            detail.setDeviceName(device.getDeviceName());
            detail.setAvailability(round(availability * 100, 2));
            detail.setPerformance(round(performance * 100, 2));
            detail.setQuality(round(quality * 100, 2));
            detail.setOee(round(oee * 100, 2));
            details.add(detail);
        }
        
        int count = devices.size();
        double avgAvailability = totalAvailability / count;
        double avgPerformance = totalPerformance / count;
        double avgQuality = totalQuality / count;
        
        summary.setAvailability(round(avgAvailability * 100, 2));
        summary.setPerformance(round(avgPerformance * 100, 2));
        summary.setQuality(round(avgQuality * 100, 2));
        summary.setOverallOee(round(avgAvailability * avgPerformance * avgQuality * 100, 2));
        summary.setPlannedTimeMinutes(totalPlannedTime);
        summary.setDowntimeMinutes(totalDowntime);
        summary.setDeviceOeeDetails(details);

        return summary;
    }

    @Override
    public AndonDashboardDTO.UtilizationSummary getUtilizationSummary(String productLineCode) {
        AndonDashboardDTO.UtilizationSummary summary = new AndonDashboardDTO.UtilizationSummary();
        
        // 查询设备列表
        BaseDeviceLedger query = new BaseDeviceLedger();
        query.setIsFlag(1L);
        if (StringUtils.isNotEmpty(productLineCode)) {
            query.setProductLineCode(productLineCode);
        }
        List<BaseDeviceLedger> devices = baseDeviceLedgerMapper.selectBaseDeviceLedgerList(query);
        
        if (devices == null || devices.isEmpty()) {
            summary.setOverallUtilization(0);
            summary.setLineUtilizations(new ArrayList<>());
            return summary;
        }

        // 按产线分组
        Map<String, List<BaseDeviceLedger>> lineDevices = devices.stream()
                .filter(d -> StringUtils.isNotEmpty(d.getProductLineCode()))
                .collect(Collectors.groupingBy(BaseDeviceLedger::getProductLineCode));

        long totalRunning = 0, totalPlanned = 0;
        List<AndonDashboardDTO.LineUtilization> lineUtilizations = new ArrayList<>();

        for (Map.Entry<String, List<BaseDeviceLedger>> entry : lineDevices.entrySet()) {
            List<BaseDeviceLedger> lineDeviceList = entry.getValue();
            long linePlanned = 0;
            long lineRunning = 0;
            
            for (BaseDeviceLedger device : lineDeviceList) {
                linePlanned += (long) queryLatestDoubleValue(device.getDeviceCode(), "机台状态-总计划生产时间");
                lineRunning += (long) queryLatestDoubleValue(device.getDeviceCode(), "机台状态-实际生产时间");
            }
            
            totalRunning += lineRunning;
            totalPlanned += linePlanned;

            AndonDashboardDTO.LineUtilization lu = new AndonDashboardDTO.LineUtilization();
            lu.setProductLineCode(entry.getKey());
            lu.setProductLineName(lineDeviceList.get(0).getProductLineName());
            lu.setRunningMinutes(lineRunning);
            lu.setPlannedMinutes(linePlanned);
            lu.setUtilization(calcRate(lineRunning, linePlanned));
            lineUtilizations.add(lu);
        }

        summary.setOverallUtilization(calcRate(totalRunning, totalPlanned));
        summary.setLineUtilizations(lineUtilizations);

        return summary;
    }

    @Override
    public AndonDashboardDTO.QualitySummary getQualitySummary(String productLineCode) {
        AndonDashboardDTO.QualitySummary summary = new AndonDashboardDTO.QualitySummary();
        
        // 获取今日日期范围
        Date todayStart = DateUtils.parseDate(DateUtils.getDate());
        Date todayEnd = DateUtils.addDays(todayStart, 1);
        
        // 查询今日质检记录
        ProductionReportQualityInspection query = new ProductionReportQualityInspection();
        query.setBeginBeginTime(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", todayStart));
        query.setEndBeginTime(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", todayEnd));
        if (StringUtils.isNotEmpty(productLineCode)) {
            query.setStationCode(productLineCode);
        }
        
        List<ProductionReportQualityInspection> qualityList = reportQualityInspectionMapper.selectReportQualityInspectionList(query);
        
        if (qualityList == null) {
            qualityList = new ArrayList<>();
        }
        
        // 按产线分组统计
        Map<String, List<ProductionReportQualityInspection>> lineQualityMap = new HashMap<>();
        for (ProductionReportQualityInspection inspection : qualityList) {
            String lineCode = inspection.getStationCode();
            if (StringUtils.isNotEmpty(lineCode)) {
                lineQualityMap.computeIfAbsent(lineCode, k -> new ArrayList<>()).add(inspection);
            }
        }
        
        long todayOutput = 0, todayGood = 0, todayDefect = 0;
        List<AndonDashboardDTO.LineQuality> lineQualities = new ArrayList<>();
        
        // 按产线统计良品和不良品ui
        for (Map.Entry<String, List<ProductionReportQualityInspection>> entry : lineQualityMap.entrySet()) {
            List<ProductionReportQualityInspection> lineInspections = entry.getValue();
            long lineGood = 0;
            long lineDefect = 0;
            
            for (ProductionReportQualityInspection inspection : lineInspections) {
                // treatmentMeasure: 3=合格(良品), 1=返修(不良品)
                if ("3".equals(inspection.getTreatmentMeasure())) {
                    lineGood++;
                } else if ("1".equals(inspection.getTreatmentMeasure())) {
                    lineDefect++;
                }
            }
            
            long lineOutput = lineGood + lineDefect;
            double lineYieldRate = lineOutput > 0 ? (lineGood * 100.0 / lineOutput) : 0;
            
            todayOutput += lineOutput;
            todayGood += lineGood;
            todayDefect += lineDefect;
            
            AndonDashboardDTO.LineQuality lq = new AndonDashboardDTO.LineQuality();
            lq.setProductLineCode(entry.getKey());
            lq.setProductLineName(lineInspections.get(0).getProductLineName());
            lq.setOutput(lineOutput);
            lq.setGoodCount(lineGood);
            lq.setDefectCount(lineDefect);
            lq.setYieldRate(round(lineYieldRate, 2));
            lineQualities.add(lq);
        }
        
        double todayYieldRate = todayOutput > 0 ? (todayGood * 100.0 / todayOutput) : 0;
        
        summary.setTodayOutput(todayOutput);
        summary.setTodayGoodCount(todayGood);
        summary.setTodayDefectCount(todayDefect);
        summary.setTodayYieldRate(round(todayYieldRate, 2));
        summary.setMonthYieldRate(round(todayYieldRate, 2)); // 暂时使用今日良品率
        summary.setLineQualities(lineQualities);

        return summary;
    }

    @Override
    public AndonDashboardDTO.AndonEventSummary getAndonEventSummary(String productLineCode) {
        AndonDashboardDTO.AndonEventSummary summary = new AndonDashboardDTO.AndonEventSummary();
        
        // 查询今日安灯事件
        AndonEvent query = new AndonEvent();
        query.setIsFlag(AnDonConstants.FLAG_VALID);
        if (StringUtils.isNotEmpty(productLineCode)) {
            query.setProductLineCode(productLineCode);
        }
        List<AndonEvent> events = andonEventMapper.selectAndonEventList(query);
        
        if (events == null) events = new ArrayList<>();

        // 获取今日日期范围
        Date todayStart = DateUtils.parseDate(DateUtils.getDate());
        Date todayEnd = DateUtils.addDays(todayStart, 1);

        // 筛选今日事件
        List<AndonEvent> todayEvents = events.stream()
                .filter(e -> e.getCreateTime() != null && 
                        !e.getCreateTime().before(todayStart) && 
                        e.getCreateTime().before(todayEnd))
                .collect(Collectors.toList());

        int pending = 0, processing = 0, resolved = 0;
        long totalResponseMs = 0, totalResolveMs = 0;
        int responseCount = 0, resolveCount = 0;
        Map<String, int[]> typeStats = new HashMap<>(); // [total, pending, resolved]

        for (AndonEvent event : todayEvents) {
            String status = event.getEventStatus();
            if (AnDonConstants.EventStatus.PENDING.equals(status)) {
                pending++;
            } else if (AnDonConstants.EventStatus.PROCESSING.equals(status)) {
                processing++;
            } else if (AnDonConstants.EventStatus.RESOLVED.equals(status)) {
                resolved++;
            }

            // 计算响应时间
            if (event.getResponseStartTime() != null && event.getCreateTime() != null) {
                totalResponseMs += event.getResponseStartTime().getTime() - event.getCreateTime().getTime();
                responseCount++;
            }

            // 计算解决时间
            if (event.getResponseEndTime() != null && event.getCreateTime() != null) {
                totalResolveMs += event.getResponseEndTime().getTime() - event.getCreateTime().getTime();
                resolveCount++;
            }

            // 按类型统计
            String typeCode = event.getCallTypeCode();
            if (StringUtils.isNotEmpty(typeCode)) {
                typeStats.computeIfAbsent(typeCode, k -> new int[3]);
                typeStats.get(typeCode)[0]++;
                if (AnDonConstants.EventStatus.PENDING.equals(status)) {
                    typeStats.get(typeCode)[1]++;
                } else if (AnDonConstants.EventStatus.RESOLVED.equals(status)) {
                    typeStats.get(typeCode)[2]++;
                }
            }
        }

        summary.setTodayTotal(todayEvents.size());
        summary.setPendingCount(pending);
        summary.setProcessingCount(processing);
        summary.setResolvedCount(resolved);
        summary.setAvgResponseMinutes(responseCount > 0 ? round(totalResponseMs / (responseCount * 60000.0), 2) : 0);
        summary.setAvgResolveMinutes(resolveCount > 0 ? round(totalResolveMs / (resolveCount * 60000.0), 2) : 0);

        // 类型统计列表
        List<AndonDashboardDTO.EventTypeStats> eventTypeStats = new ArrayList<>();
        for (Map.Entry<String, int[]> entry : typeStats.entrySet()) {
            AndonDashboardDTO.EventTypeStats ets = new AndonDashboardDTO.EventTypeStats();
            ets.setCallTypeCode(entry.getKey());
            ets.setCallTypeName(entry.getKey()); // 实际应从字典获取名称
            ets.setCount(entry.getValue()[0]);
            ets.setPendingCount(entry.getValue()[1]);
            ets.setResolvedCount(entry.getValue()[2]);
            eventTypeStats.add(ets);
        }
        summary.setEventTypeStats(eventTypeStats);

        return summary;
    }

    private double calcRate(long numerator, long denominator) {
        if (denominator == 0) return 0;
        return round((double) numerator / denominator * 100, 2);
    }

    private double parseDouble(String value) {
        if (StringUtils.isEmpty(value)) return 0;
        try {
            return Double.parseDouble(value);
        } catch (NumberFormatException e) {
            return 0;
        }
    }

    private long parseLong(String value) {
        if (StringUtils.isEmpty(value)) return 0;
        try {
            return Long.parseLong(value);
        } catch (NumberFormatException e) {
            return 0;
        }
    }

    private double round(double value, int places) {
        return BigDecimal.valueOf(value)
                .setScale(places, RoundingMode.HALF_UP)
                .doubleValue();
    }

    private double queryLatestDoubleValue(String deviceCode, String paramName) {
        BaseDeviceParamVal latestVal = deviceParamReadFacade.getLatestParamValue(deviceCode, null, paramName);
        return latestVal == null ? 0D : parseDouble(latestVal.getParamValue());
    }

    private long queryLatestLongValue(String deviceCode, String paramName) {
        BaseDeviceParamVal latestVal = deviceParamReadFacade.getLatestParamValue(deviceCode, null, paramName);
        return latestVal == null ? 0L : parseLong(latestVal.getParamValue());
    }

    private Number getNumber(Map<String, Object> data, String upperKey, String lowerKey) {
        Object value = data.get(upperKey);
        if (value == null) {
            value = data.get(lowerKey);
        }
        return value instanceof Number ? (Number) value : null;
    }
}
