package com.usky.rule.service.impl;

import com.usky.rule.domain.RuleEngine;
import com.usky.rule.util.JsonUtil;
import com.usky.rule.vo.RuleEngineDTO;
import com.usky.rule.enums.ActionTypeEnum;
import com.usky.rule.enums.TriggerTypeEnum;
import com.usky.rule.vo.RuleEngineDetail;
import com.usky.rule.vo.action.RuleEngineAction;
import com.usky.rule.vo.constraint.CronConstraint;
import com.usky.rule.vo.constraint.DeviceConstraint;
import com.usky.rule.vo.log.RuleEngineDetailLog;
import com.usky.rule.vo.trigger.CronTrigger;
import com.usky.rule.cache.DeviceTriggerIncludeMinuteCache;
import com.usky.rule.config.CronTaskManager;
import com.usky.rule.crons.TriggerCronTask;
import com.usky.rule.service.RuleEngineDetailService;
import com.usky.rule.util.RuleEngineUtil;
import com.usky.rule.service.RuleEngineService;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

@Service("ruleEngineDetailService")
public class RuleEngineDetailServiceImpl implements RuleEngineDetailService {
    private CronTaskManager cronTaskManager;
    private TriggerCronTask triggerCronTask;
    private RuleEngineService ruleEngineService;
    private RuleEngineUtil ruleEngineUtil;
    private DeviceTriggerIncludeMinuteCache historyRecordCache;

    public Boolean save(RuleEngineDTO dto) {
        if (dto.getStatus() != null && dto.getStatus() == 0) {
            this.triggerCronTask.removeDeviceConsumptionCache(dto.getId());
            return true;
        }
        if (StringUtils.isBlank(dto.getDetail())) {
            this.triggerCronTask.removeDeviceConsumptionCache(dto.getId());
            return true;
        }
        RuleEngineDetail ruleEngineDetail = (RuleEngineDetail)JsonUtil.toObject(dto.getDetail(), RuleEngineDetail.class);
        // 必须先同步缓存：与 actions 是否为空无关，否则仅改触发器/去掉能耗时仍沿用旧 consumption 列表
        this.triggerCronTask.setDeviceConsumptionCache(dto.getId(), ruleEngineDetail);
        List<RuleEngineAction> actions = this.ruleEngineService.getActions(ruleEngineDetail.getActions());
        if (actions != null && !actions.isEmpty()) {
            this.createCronTask(dto, ruleEngineDetail, actions);
        }
        return true;
    }

    private void createCronTask(RuleEngineDTO dto, RuleEngineDetail ruleEngineDetail, List<RuleEngineAction> actions) {
        List<CronTrigger> cronTriggers = this.ruleEngineService.getCronTriggers(ruleEngineDetail.getTriggers());
        if (cronTriggers != null) {
            List<CronConstraint> cronConstraints = this.ruleEngineService.getCronConstraints(ruleEngineDetail.getConstraints());
            List<DeviceConstraint> deviceConstraints = this.ruleEngineService.getDeviceConstraints(ruleEngineDetail.getConstraints());
            this.addRuleEngineJobs(dto.getId(), dto.getProjectId(), dto.getSpaceId(), actions, cronTriggers, cronConstraints, deviceConstraints);
        }

    }

    private void addRuleEngineJobs(Long id, Long projectId, Long spaceId, List<RuleEngineAction> actions, List<CronTrigger> cronTriggers, List<CronConstraint> cronConstraints, List<DeviceConstraint> deviceConstraints) {
        TriggerCronTask.addCronJob(id, projectId, spaceId, cronTriggers, cronConstraints, deviceConstraints, actions, this.cronTaskManager);
    }

    public Boolean update(RuleEngineDTO dto) {
        return this.cronTaskManager.deleteAllJobsInJobGroup(dto.getId()) ? this.save(dto) : false;
    }

    public Boolean remove(Long id) {
        Assert.notNull(id, "id不能为空");
        this.historyRecordCache.deleteConditions(id);
        this.triggerCronTask.removeDeviceConsumptionCache(id);
        return this.cronTaskManager.deleteAllJobsInJobGroup(id);
    }

    public Boolean manualPerformDeviceControl(Long id) {
        RuleEngine ruleEngine = (RuleEngine)this.ruleEngineService.getById(id);
        Assert.notNull(ruleEngine, "规则引擎不存在");
        RuleEngineDetail ruleEngineDetail = getRuleEngineDetail(ruleEngine);
        if (ruleEngineDetail == null) {
            return true;
        } else {
            List<RuleEngineAction> actions = this.ruleEngineService.getActions(ruleEngineDetail.getActions());
            if (actions != null && !actions.isEmpty()) {
                this.ruleEngineUtil.performMultipleDevicesControl(id, false, TriggerTypeEnum.DEVICE.getType(), ruleEngine.getProjectId(), (Long)null, actions, new RuleEngineDetailLog());
                return true;
            } else {
                return true;
            }
        }
    }

    private static RuleEngineDetail getRuleEngineDetail(RuleEngine ruleEngine) {
        return StringUtils.isNotBlank(ruleEngine.getDetail()) ? (RuleEngineDetail)JsonUtil.toObject(ruleEngine.getDetail(), RuleEngineDetail.class) : null;
    }

    public RuleEngineDetailServiceImpl(final CronTaskManager cronTaskManager, final TriggerCronTask triggerCronTask, final RuleEngineService ruleEngineService, final RuleEngineUtil ruleEngineUtil, final DeviceTriggerIncludeMinuteCache historyRecordCache) {
        this.cronTaskManager = cronTaskManager;
        this.triggerCronTask = triggerCronTask;
        this.ruleEngineService = ruleEngineService;
        this.ruleEngineUtil = ruleEngineUtil;
        this.historyRecordCache = historyRecordCache;
    }
}
