package com.dcs.hnyz.service.impl;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import com.dcs.common.utils.DateUtils;
import com.dcs.equipment.utils.ModbusUtil;
import com.dcs.hnyz.cache.CacheCenter;
import com.dcs.hnyz.domain.bo.CachedAction;
import com.dcs.hnyz.domain.condition.Condition;
import com.dcs.hnyz.domain.condition.ConditionGroup;
import com.dcs.hnyz.domain.condition.ConditionItem;
import com.dcs.hnyz.domain.vo.EquipmentParamFormVO;
import com.dcs.hnyz.enums.ActionTypeEnum;
import com.dcs.hnyz.enums.OperationType;
import com.dcs.hnyz.enums.TriggerTypeEnum;
import com.dcs.hnyz.service.IActionBindingService;
import com.dcs.hnyz.service.IEquipmentParamService;
import com.dcs.hnyz.cache.builder.ActionCacheBuilder;
import com.dcs.hnyz.cache.builder.RegisterCodeMapBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import com.dcs.hnyz.mapper.ActionConfigMapper;
import com.dcs.hnyz.domain.ActionConfig;
import com.dcs.hnyz.service.IActionConfigService;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import static com.dcs.framework.datasource.DynamicDataSourceContextHolder.log;

/**
 * 动作配置管理Service业务层处理
 *
 * @author hmy
 * @date 2025-04-28
 */
@Service
public class ActionConfigServiceImpl implements IActionConfigService {
    @Resource
    private ActionConfigMapper actionConfigMapper;
    @Autowired
    private ActionCacheBuilder actionCacheBuilder;
    @Autowired
    private RegisterCodeMapBuilder registerCodeMapBuilder;
    @Autowired
    private IEquipmentParamService equipmentParamService;
    @Autowired
    private IActionBindingService actionBindingService;

    //共享线程池
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(4);


    /**
     * 查询动作配置管理
     *
     * @param actionId 动作配置管理主键
     * @return 动作配置管理
     */
    @Override
    public ActionConfig selectActionConfigByActionId(Long actionId) {
        return actionConfigMapper.selectById(actionId);
    }

    /**
     * 查询动作配置管理列表
     *
     * @param actionConfig 动作配置管理
     * @return 动作配置管理
     */
    @Override
    public List<ActionConfig> selectActionConfigList(ActionConfig actionConfig) {
        return actionConfigMapper.selectActionConfigList(actionConfig);
    }

    /**
     * 新增动作配置管理
     *
     * @param actionConfig 动作配置管理
     * @return 结果
     */
    @Override
    public int insertActionConfig(ActionConfig actionConfig) {
        actionConfig.setCreateTime(DateUtils.getNowDate());
        int i = actionConfigMapper.insert(actionConfig);
        if (i > 0) {//更新缓存
            System.out.println(actionConfig);
            try {
                actionCacheBuilder.addCache(actionConfig);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return i;
    }

    /**
     * 修改动作配置管理
     *
     * @param actionConfig 动作配置管理
     * @return 结果
     */
    @Override
    public int updateActionConfig(ActionConfig actionConfig) {
        actionConfig.setUpdateTime(DateUtils.getNowDate());
        int i = actionConfigMapper.updateById(actionConfig);
        if (i > 0) {//更新缓存
            try {
                actionCacheBuilder.updateCache(actionConfig);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return i;
    }

    /**
     * 批量删除动作配置管理
     *
     * @param actionIds 需要删除的动作配置管理主键
     * @return 结果
     */
    @Override
    public int deleteActionConfigByActionIds(Long[] actionIds) {
        List<Long> idList = Arrays.asList(actionIds);
        int i = actionConfigMapper.deleteBatchIds(idList);
        if (i > 0) {
            for (Long id : idList) {
                try {
                    actionCacheBuilder.deleteCache(id);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return i;
    }

    /**
     * 删除动作配置管理信息
     *
     * @param actionId 动作配置管理主键
     * @return 结果
     */
    @Override
    public int deleteActionConfigByActionId(Long actionId) {
        int i=actionConfigMapper.deleteById(actionId);
        if (i > 0) {//更新缓存
            try {
                actionCacheBuilder.deleteCache(actionId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return i;
    }

    /**
     * 递归判断条件是否满足(核心逻辑)
     * @param condition 条件
     * @param deviceMap 设备ID到寄存器code的映射
     * @param plcData   实时数据
     * @return 是否满足条件
     */
    public boolean evaluate(Condition condition,
                            Map<Integer, String> deviceMap,
                            Map<String, EquipmentParamFormVO> plcData) {
        if (condition instanceof ConditionGroup) {//判断是否为组合条件
            ConditionGroup group = (ConditionGroup) condition;
            boolean result = "AND".equalsIgnoreCase(group.getOperator());
            for (Condition child : group.getConditions()) {//递归判断子条件
                boolean childResult = evaluate(child, deviceMap, plcData);
                if ("AND".equalsIgnoreCase(group.getOperator())) {
                    result = result && childResult;
                    if (!result) break; // 短路优化
                } else {
                    result = result || childResult;
                    if (result) break;
                }
            }
            return result;
        } else if (condition instanceof ConditionItem) {// 判断是否为叶子条件
            ConditionItem item = (ConditionItem) condition;
            int deviceId = item.getDevice();
            String operator = item.getOperator();
            String expectedValue = item.getValue();

            String code = deviceMap.get(deviceId);
            if (code == null) return false;

            EquipmentParamFormVO param = plcData.get(code);
            if (param == null || param.getValue() == null) return false;

            String actualValue = param.getValue().toString();//实际值
            //判断条件是否满足
            try {
                OperationType op = OperationType.fromCode(operator);
                return op.apply(actualValue, expectedValue);
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
        return false;
    }

    @Scheduled(fixedRate = 3000) // 每 3 秒执行一次
    public void checkActions() {
//        模拟数据
//        EquipmentParamFormVo param = new EquipmentParamFormVo();
//        param.setCode("D2kxh");
//        param.setValue(true);
//        CacheCenter.registerNowDataMap.put("D2kxh",param);

        Map<String, EquipmentParamFormVO> plcData = CacheCenter.registerNowDataMap;
        for (CachedAction action : actionCacheBuilder.getCache().values()) {
            ActionConfig actionConfig = action.getActionConfig();//动作配置
            //只处理条件触发事件
            if (!TriggerTypeEnum.CONDITION_TRIGGER.getCode().equals(actionConfig.getTriggerType())) {
                continue;
            }
            //对于已触发的事件不在重复触发
            if (action.isTrigger()) continue;
//            boolean match = evaluate(action.getCondition(), registerCodeMapBuilder.getRegisterCodeMap(),paramListToMap(ModbusTcpTask.getBroadCastEquipmentParamFormVOList()));
            boolean match = evaluate(action.getCondition(), registerCodeMapBuilder.getRegisterCodeMap(), plcData);
            //修改缓存内动作触发状态
            actionCacheBuilder.setTrigger(actionConfig.getActionId(), match);
            if (match) {
                log.info("动作命中：ID={}, 缓存={}", actionConfig.getActionId(), action.getCondition());
                triggerActionDelay(actionConfig);
                //处理同步触发事件
                List<Long> longs = actionBindingService.selectBindActionIdsByActionId(actionConfig.getActionId());
                for (Long actionId : longs) {
                    //对应同步事件触发要满足的动作配置
                    CachedAction actionSync = actionCacheBuilder.getCache().get(actionId);
                    //对于已触发的事件不在重复触发
                    if (actionSync.isTrigger()) continue;
                    ActionConfig actionConfigSync=actionSync.getActionConfig();
                    Condition condition = actionSync.getCondition();//动作条件
                    boolean matchSync = evaluate(condition, registerCodeMapBuilder.getRegisterCodeMap(), plcData);
                    if (matchSync) {
                        log.info("动作命中：ID={}, 缓存={}", actionConfigSync.getActionId(), actionSync.getCondition());
                        triggerActionDelay(actionConfigSync);
                    }
                    actionCacheBuilder.setTrigger(actionConfigSync.getActionId(), matchSync);
                }
            }
        }
    }

    /**
     * 延时处理
     * @param actionConfig 动作配置
     */
    private void triggerActionDelay(ActionConfig actionConfig) {
        //延时处理
        if (actionConfig.getTriggerDelay() > 0) {
            scheduler.schedule(() -> {
                log.info("延时动作执行：ID={}", actionConfig.getActionId());
                executeAction(actionConfig);
            }, actionConfig.getTriggerDelay(), TimeUnit.SECONDS);
        } else {
            log.info("动作执行：ID={}", actionConfig.getActionId());
            executeAction(actionConfig);
        }
    }


    /**
     * 执行动作逻辑
     * @param actionConfig 动作配置
     */
    public void executeAction(ActionConfig actionConfig) {
        //动作执行对应寄存器的code
        Integer address = equipmentParamService.getSetCodeByParentId(actionConfig.getEquipmentId());
        if (address == null) {
            log.info("动作执行对应寄存器的code为空");
            return;
        }
        //动作类型
        ActionTypeEnum type;
        try {
            type = ActionTypeEnum.valueOf(actionConfig.getActionType());
        } catch (IllegalArgumentException e) {
            log.warn("未知动作类型：{}", actionConfig.getActionType());
            return;
        }
        try {
            switch (type) {
                case SET_FLOAT_VALUE:
                    ModbusUtil.setRegisterFloatValue(1, address, Float.parseFloat(actionConfig.getValue()));
                    break;
                case ON:
//                    System.out.println("on" + address);
                    ModbusUtil.setCoilValue(1, address, true);
                    break;
                case OFF:
//                    System.out.println("off" + address);
                    ModbusUtil.setCoilValue(1, address, false);
                    break;
                case SET_INT_VALUE:
                    ModbusUtil.setRegisterValue(1, address, Integer.parseInt(actionConfig.getValue()));
                    break;
                default:
                    log.warn("未处理的动作类型：{}", type);
                    break;
            }
        } catch (Exception e) {
            log.error("执行动作失败，类型={}，寄存器地址={}，值={}，异常信息：{}",
                    type, address, actionConfig.getValue(), e.getMessage(), e);
        }
    }

    @PreDestroy
    public void shutdownScheduler() {
        scheduler.shutdown();
    }

}
