package com.fizz.business.comm.OPC;

import com.fizz.business.constants.enums.ExitCutTypeEnum;
import com.fizz.business.constants.enums.OpcMessageType;
import com.fizz.business.domain.msg.*;
import com.fizz.business.scheduled.BaseSchedule;
import com.fizz.business.service.hanle.OpcReceiverHandler;
import com.fizz.business.service.ProStoppageService;
import com.fizz.business.domain.ProStoppage;
import com.kangaroohy.milo.model.ReadWriteEntity;
import com.kangaroohy.milo.service.MiloService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

import java.lang.reflect.Field;
import java.time.Duration;
import java.time.LocalDateTime;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.fizz.business.service.manager.OpcMessageIdsManager.*;

@Slf4j
@Component
@ConditionalOnProperty(prefix = "kangaroohy.milo", name = "enabled", havingValue = "true")
public class MessageReceiveSchedule extends BaseSchedule {

    @Resource
    MiloService miloService;

    @Resource
    private OpcReceiverHandler opcReceiverHandler;

    @Resource
    private ProStoppageService proStoppageService;

    /**
     * 低速监控状态
     */
    private LocalDateTime lowSpeedStartTime;
    private boolean stopRecorded = false;
    private Long currentStopId;

    /**
     * 恢复监控状态
     */
    private LocalDateTime highSpeedStartTime;

    @Scheduled(fixedDelay = 1000)
    public void L1L2LineMeasure() {
        try {

            AppMeasureEntryMessage entry = new AppMeasureEntryMessage();
            writeMessage(entry,entryLineMeasureIds);

            AppMeasureCoatMessage coat = new AppMeasureCoatMessage();
            writeMessage(coat,procLineMeasureIds);

            AppMeasureFurnaceMessage fur = new AppMeasureFurnaceMessage();
            writeMessage(fur,furLineMeasureIds);

            AppMeasureExitMessage exit = new AppMeasureExitMessage();
            writeMessage(exit,exitLineMeasureIds);

            AppMeasureMessage msg = new AppMeasureMessage();
            msg.setAppMeasureEntryMessage(entry);
            msg.setAppMeasureCoatMessage(coat);
            msg.setAppMeasureFurnaceMessage(fur);
            msg.setAppMeasureExitMessage(exit);

            monitorStripSpeed(entry);

            opcReceiverHandler.onMessageReceived(OpcMessageType.APP_MEASURE,msg);

        } catch (Exception e) {
//            throw new RuntimeException(e);
        }
    }

    private void writeMessage(OpcMessage msg, Map<String,String> msgIds) throws Exception {
        List<String> ids = new ArrayList<>(msgIds.keySet());
        ids.remove("trigger");
        List<ReadWriteEntity> nodes =  miloService.readFromOpcUa(ids);
        nodes.forEach(item->{
            String fieldName = msgIds.get(item.getIdentifier());
            if (fieldName != null) {
                try {
                    Field field = msg.getClass().getDeclaredField(fieldName);
                    if (field.getType() == ExitCutTypeEnum.class) {
                        // 使用枚举类的自定义方法
                        field.setAccessible(true);
                        ExitCutTypeEnum enumValue = ExitCutTypeEnum.fromCode((int)item.getValue());
                        field.set(msg, enumValue);
                    } else {
                        // 其他类型正常处理
                        BeanUtils.setProperty(msg, fieldName, item.getValue());
                    }
                } catch (Exception e) {
                    log.error("BeanUtils设置属性失败: {}", fieldName, e);
                }
            }
        });
    }

    /**
     * stripSpeed<5 持续5分钟判定停机，>5 持续1分钟结束停机并更新维持时间
     */
    private void monitorStripSpeed(AppMeasureEntryMessage entry) {
        if (entry == null || entry.getStripSpeed() == null) {
            resetSpeedFlags();
            return;
        }

        boolean lowSpeed = entry.getStripSpeed().compareTo(BigDecimal.valueOf(5)) < 0;
        LocalDateTime now = LocalDateTime.now();

        if (lowSpeed) {
            highSpeedStartTime = null; // 重置恢复计时
            if (lowSpeedStartTime == null) {
                lowSpeedStartTime = now;
            }
            // 低速已持续超过5分钟且尚未入库，则新增停机记录
            if (!stopRecorded && Duration.between(lowSpeedStartTime, now).toMinutes() >= 5) {
                ProStoppage stoppage = new ProStoppage();
                stoppage.setStartDate(lowSpeedStartTime);
                stoppage.setDuration(BigDecimal.ZERO); // 初始为0，恢复后再更新
                stoppage.setStopType("AUTO_LOW_SPEED");
                stoppage.setRemark("stripSpeed<5 自动停机");
                if (proStoppageService.save(stoppage)) {
                    currentStopId = stoppage.getStopid();
                    stopRecorded = true;
                    log.info("自动新增低速停机记录，stopId={} start={}", currentStopId, lowSpeedStartTime);
                } else {
                    log.warn("自动新增低速停机记录失败");
                }
            }
        } else {
            lowSpeedStartTime = null;
            if (stopRecorded) {
                if (highSpeedStartTime == null) {
                    highSpeedStartTime = now;
                }
                if (Duration.between(highSpeedStartTime, now).toMinutes() >= 1 && currentStopId != null) {
                    ProStoppage update = new ProStoppage();
                    update.setStopid(currentStopId);
                    update.setEndDate(now);
                    // duration 以秒存储
                    ProStoppage existing = proStoppageService.getById(currentStopId);
                    LocalDateTime start = existing != null && existing.getStartDate() != null ? existing.getStartDate() : highSpeedStartTime;
                    long seconds = Duration.between(start, now).getSeconds();
                    update.setDuration(BigDecimal.valueOf(seconds));
                    proStoppageService.updateById(update);
                    log.info("低速停机结束更新，stopId={} duration={}s", currentStopId, seconds);
                    resetSpeedFlags();
                }
            } else {
                highSpeedStartTime = null;
            }
        }
    }

    private void resetSpeedFlags() {
        lowSpeedStartTime = null;
        highSpeedStartTime = null;
        // 不重置 stopRecorded/currentStopId，避免短暂无值时丢失状态
    }
}
