package com.usky.rule.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.usky.common.security.utils.SecurityUtils;
import com.usky.rule.domain.DmpProductCommand;
import com.usky.rule.domain.RuleEngineLog;
import com.usky.rule.service.*;
import com.usky.rule.enums.ActionTypeEnum;
import com.usky.rule.vo.action.AlarmEventAction;
import com.usky.rule.vo.action.DeviceControlAction;
import com.usky.rule.vo.action.RuleEngineAction;
import com.usky.rule.vo.log.*;
import com.usky.rule.vo.visualization.AlarmSimpleVO;
import com.usky.rule.vo.visualization.SimpleVO;
import com.usky.rule.listeners.CommonListener;
import java.time.LocalDateTime;
import java.time.Year;
import java.time.format.DateTimeFormatter;
import java.util.*;

import com.usky.rule.vo.Result;
import com.usky.transfer.RemoteTransferService;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

@Component
@Service
public class RuleEngineUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(CommonListener.class);
    private RuleEngineLogService ruleEngineLogService;
    private RuleEngineService ruleEngineService;
    @Autowired
    private RemoteTransferService remoteTransferService;
    @Autowired
    private DmpProductCommandService dmpProductCommandService;

    @Value("${alarm.url}")
    private String alarmUrl;

    public static String getJobGroup(Long ruleEngineId) {
        return "trigger-" + ruleEngineId;
    }

    public static String getTriggerCronJobName(Integer index) {
        return "job-" + index;
    }

    public void performMultipleDevicesControl(Long ruleEngineId, boolean isAuto, String triggerType, Long projectId, Long spaceId, List<RuleEngineAction> actionList, RuleEngineDetailLog ruleEngineDetail) {
        List<BaseLog> baseLogs = new ArrayList();
        ruleEngineDetail.setActions(baseLogs);
        LocalDateTime now = LocalDateTime.now();
        Set<String> deviceActionTypes = new HashSet(2);
        String ruleEngineName = this.ruleEngineService.getName(ruleEngineId);

        RuleEngineLog ruleEngineLog = new RuleEngineLog();

        for(RuleEngineAction ruleEngineAction : actionList) {
            if (ActionTypeEnum.DEVICE_CONTROL.getType().equals(ruleEngineAction.getType())) {
                DeviceControlAction deviceControlAction = (DeviceControlAction)ruleEngineAction;
                deviceActionTypes.add("deviceControl");
                BaseLog baseLog = new BaseLog();
                baseLog.setType(ActionTypeEnum.DEVICE_CONTROL.getType());
                ControlAction controlAction = new ControlAction();
                this.performSingleDeviceControl(deviceControlAction, controlAction, now);
                baseLog.setDetail(controlAction);
                baseLogs.add(baseLog);
                ruleEngineLog.setTenantId(deviceControlAction.getDevices().get(0).getTenantId());
            } else if (ActionTypeEnum.ALARM_EVENT.getType().equals(ruleEngineAction.getType())) {
                this.generateAlarmEvent(ruleEngineId, ruleEngineName, projectId, spaceId, Collections.singletonList(ruleEngineAction));
                deviceActionTypes.add("alarmEvent");
                BaseLog baseLog = new BaseLog();
                baseLog.setType(ActionTypeEnum.ALARM_EVENT.getType());
                baseLog.setDetail(getAlarmActionLog(now, (AlarmEventAction)ruleEngineAction));
                baseLogs.add(baseLog);
                ruleEngineLog.setTenantId(((AlarmEventAction) ruleEngineAction).getDevices().get(0).getTenantId());
            }
        }

        ruleEngineLog.setDetail(JsonUtil.toJson(ruleEngineDetail));
        ruleEngineLog.setRuleEngineId(ruleEngineId);
        ruleEngineLog.setRuleEngineName(ruleEngineName);
        ruleEngineLog.setAutoTrigger((byte) (isAuto ? 1 : 0));
        ruleEngineLog.setProjectId(projectId);
        ruleEngineLog.setAction(String.join(",", deviceActionTypes));
        ruleEngineLog.setTriggerType(triggerType);
        ruleEngineLog.setUpdateTime(now);
        ruleEngineLog.setCreateTime(now);
        ruleEngineLog.setCreatedBy("admin");
        ruleEngineLog.setUpdatedBy("admin");
        if(!SecurityUtils.getUsername().isEmpty()) {
            ruleEngineLog.setCreatedBy(SecurityUtils.getUsername());
            ruleEngineLog.setUpdatedBy(SecurityUtils.getUsername());
            ruleEngineLog.setTenantId(SecurityUtils.getTenantId());
        }
        ruleEngineLog.setTime(now);
        this.ruleEngineLogService.save(ruleEngineLog);

    }

    @NotNull
    private static AlarmActionLog getAlarmActionLog(LocalDateTime now, AlarmEventAction ruleEngineAction) {
        AlarmActionLog alarmActionLog = new AlarmActionLog();
        List<AlarmEventLog> alarmEventLogs = new ArrayList();
        alarmActionLog.setAlarms(alarmEventLogs);
        alarmActionLog.setTime(DateTimeUtil.format(now));
        AlarmEventLog alarmEventLog = new AlarmEventLog();
        alarmEventLog.setNotifiers(ruleEngineAction.getDevices());
        alarmEventLog.setLevel(String.valueOf(ruleEngineAction.getAlarmGrade()));
        alarmEventLog.setMethod(ruleEngineAction.getAlarmAttribute());
        alarmEventLogs.add(alarmEventLog);
        return alarmActionLog;
    }

    /**
     * 推送告警
     * @param ruleEngineId
     * @param ruleEngineName
     * @param projectId
     * @param spaceId
     * @param actions
     */
    public void generateAlarmEvent(Long ruleEngineId, String ruleEngineName, Long projectId, Long spaceId, List<RuleEngineAction> actions) {
        for(RuleEngineAction ruleEngineAction : actions) {
            AlarmEventAction alarmEventAction = (AlarmEventAction)ruleEngineAction;
            List<AlarmSimpleVO> devices = alarmEventAction.getDevices();
            if (devices != null && !devices.isEmpty()) {
                JSONObject jsonObject = new JSONObject();
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime now = LocalDateTime.now();
                String alarmTime = now.format(formatter);
                jsonObject.put("alarmTime",alarmTime);
                jsonObject.put("alarmType",alarmEventAction.getAlarmType());
                jsonObject.put("alarmData",0);
                jsonObject.put("alarmAttribute",alarmEventAction.getAlarmAttribute());
                jsonObject.put("alarmContent",alarmEventAction.getAlarmAttribute());
                jsonObject.put("alarmGrade",alarmEventAction.getAlarmGrade());
                jsonObject.put("productCode",alarmEventAction.getProductCode());
                for (AlarmSimpleVO device : devices) {
                    jsonObject.put("deviceId",device.getDeviceId());
                    jsonObject.put("alarmObject",device.getName());
                    jsonObject.put("alarmAddress",device.getCommAddress());

                    HttpClientUtils.doPostJson(alarmUrl,jsonObject.toJSONString());
                }
            }
        }

    }

    /**
     * 从 JSON 数组字符串中，根据 value 值获取对应的 name 值
     * @param jsonArrayStr JSON数组字符串（如：[{"name":"开","value":"1"},{"name":"关","value":"2"}]）
     * @param targetValue  要匹配的value值（如："1"）
     * @return 匹配的name值，无匹配返回空字符串
     */
    public static String getNameByValue(String jsonArrayStr, String targetValue) {
        // 1. 空值校验
        if (StringUtils.isBlank(jsonArrayStr) || StringUtils.isBlank(targetValue)) {
            return "";
        }

        // 2. 解析 JSON 数组
        JSONArray jsonArray = JSONArray.parseArray(jsonArrayStr);

        // 3. 遍历数组，匹配 value，返回对应 name（一行核心逻辑）
        return jsonArray.stream()
                .map(obj -> (JSONObject) obj)  // 转为 JSONObject
                .filter(jsonObj -> targetValue.equals(jsonObj.getString("value")))  // 匹配 value
                .findFirst()  // 获取第一个匹配项
                .map(jsonObj -> jsonObj.getString("name"))  // 提取 name
                .orElse("");  // 无匹配返回空字符串（也可改为"未知"）
    }



    public void performSingleDeviceControl(DeviceControlAction deviceControlAction, ControlAction controlAction, LocalDateTime now) {
        List<SimpleVO> devices = deviceControlAction.getDevices();
        if (devices != null && !devices.isEmpty()) {
            Integer productId = deviceControlAction.getProductId();
            String productCode = deviceControlAction.getProductCode();
            //String productCode = dmpProductService.getOne(new LambdaQueryWrapper<DmpProduct>().eq(DmpProduct::getId, productId).eq(DmpProduct::getDeleteFlag,0).eq(DmpProduct::getTenantId, SecurityUtils.getTenantId())).getProductCode();
            List<DmpProductCommand> dmpProductCommandList = Optional.ofNullable(
                    dmpProductCommandService.getBaseMapper().selectList(new LambdaQueryWrapper<DmpProductCommand>()
                            .eq(DmpProductCommand::getProductCode, productCode)))
                    .orElse(Collections.emptyList());
            List<DeviceControlAction.Functions> functions = deviceControlAction.getFunctions();
            List<Control> controls = new ArrayList();
            List<DeviceControlResult> deviceControlResults = new ArrayList();
            controlAction.setControls(controls);
            controlAction.setDevices(deviceControlResults);
            controlAction.setTime(DateTimeUtil.format(now));

            for(DeviceControlAction.Functions function : functions) {
                String identifier = function.getIdentifier();
                DmpProductCommand dmpProductCommand = dmpProductCommandList.stream()
                        .filter(cmd -> StringUtils.equals(cmd.getCommandCode(), identifier))
                        .findFirst()
                        .orElse(null);
                HashMap<String, String> functionMap = new HashMap();
                functionMap.put(identifier, function.getValue());
                Control control = new Control();
                //control.setDelaySeconds(function.getDelaySeconds());
                control.setIdentifier(identifier);
                control.setName(dmpProductCommand != null ? dmpProductCommand.getCommandName() : null);
                control.setValue(function.getValue());
                control.setValueDesc(getNameByValue(dmpProductCommand != null ? dmpProductCommand.getCommandDict() : null, function.getValue()));
                controls.add(control);

                for(SimpleVO device : devices) {
                    String id = device.getId();
                    String name = device.getName();
                    String deviceUuid = device.getDeviceUuid();
                    String gatewayUuid = device.getGatewayUuid();
                    Integer tenantId = device.getTenantId();

                    long userId = SecurityUtils.getUserId();
                    if(userId == 0){
                        userId = 1L;
                    }

                    String userName = SecurityUtils.getUsername();
                    if(userName == null){
                        userName = "admin";
                    }

                    Map<String, Object> map = new HashMap<>();
                    map.put("method", "control");
                    map.put("deviceUuid", deviceUuid);
                    Map<String, Object> map1 = new HashMap<>();
                    map1.put("commandCode", function.getIdentifier());
                    map1.put("commandValue", function.getValue());
                    map.put("params", map1);


                    DeviceControlResult deviceControlResult = new DeviceControlResult();
                    deviceControlResult.setId(id);
                    deviceControlResult.setName(name);
                    ArrayList<DeviceControlResult.Result> results = new ArrayList();
                    deviceControlResult.setResult(results);
                    deviceControlResults.add(deviceControlResult);
                    DeviceControlResult.Result result = new DeviceControlResult.Result();

                    try {
                        result.setReqTime(DateTimeUtil.format(LocalDateTime.now()));
                        Map<String,Object> responseData =  remoteTransferService.deviceControl(productCode, gatewayUuid, JSON.toJSONString(map), tenantId, userId, userName);

                        result.setCode(responseData.get("code").toString());
                    } catch (Exception e) {
                        result.setCode("200001");
                        result.setMessage(e.getMessage());
                    }

                    result.setRespTime(DateTimeUtil.format(LocalDateTime.now()));
                    results.add(result);
                }
            }

        }
    }

    public RuleEngineUtil(final RuleEngineLogService ruleEngineLogService, final RuleEngineService ruleEngineService) {
        this.ruleEngineLogService = ruleEngineLogService;
        this.ruleEngineService = ruleEngineService;
    }
}
