/*
 * 文 件 名:  EmsApiTemplate
 * 版    权:  华设设计集团股份有限公司
 * 描    述:  EMS Server API 调用模板
 * 修 改 人:  lvwenbin
 * 修改时间:  2025/12/9
 */
package com.ruoyi.ems.core;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.retrofit.Retrofit2ConverterFactory;
import com.ruoyi.ems.config.EmsConfig;
import com.ruoyi.ems.retrofit.EmsApi;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * EMS Server API 调用模板
 * 用于 ems-dev-adapter 调用 ems-server 的策略相关接口
 *
 * @author lvwenbin
 * @version [版本号, 2025/12/9]
 */
@Slf4j
public class EmsApiTemplate extends BaseApiTemplate {
    /**
     * EMS Server 地址
     */
    protected String url;

    private boolean notifyEnabled;

    /**
     * API 代理
     */
    protected final EmsApi api;

    /**
     * 异步执行线程池
     */
    private final ExecutorService asyncExecutor = Executors.newFixedThreadPool(3);

    /**
     * 构造调用模板（默认超时配置）
     *
     * @param emsConfig EMS Server 地址 (http://ip:port)
     */
    public EmsApiTemplate(EmsConfig emsConfig) {
        super.connectTimeout = emsConfig.getConnectTimeout();
        super.readTimeout = emsConfig.getReadTimeout();
        super.writeTimeout = emsConfig.getWriteTimeout();
        this.url = emsConfig.getUrl();
        this.notifyEnabled = emsConfig.isNotifyEnabled();

        OkHttpClient httpClient = getClient();
        Retrofit retrofit = new Retrofit.Builder().baseUrl(this.url)
            .addConverterFactory(Retrofit2ConverterFactory.create()).client(httpClient).build();
        this.api = retrofit.create(EmsApi.class);
    }

    // ==================== 同步调用方法 ====================

    /**
     * 通知属性值变化（同步）
     *
     * @param objCode  设备代码
     * @param attrKey  属性键
     * @param oldValue 旧值（可为null）
     * @param newValue 新值
     * @return 触发的策略数量，失败返回 -1
     */
    public int notifyAttrValueChanged(String objCode, String attrKey, Object oldValue, Object newValue) {
        if (!notifyEnabled) {
            log.debug("策略通知已禁用，跳过: obj={}, attr={}", objCode, attrKey);
            return 0;
        }

        try {
            String oldValueStr = oldValue != null ? String.valueOf(oldValue) : null;
            String newValueStr = newValue != null ? String.valueOf(newValue) : "";

            Call<String> call = api.onAttrValueChanged(objCode, attrKey, newValueStr, oldValueStr);
            Response<String> response = call.execute();

            log.debug("notifyAttrValueChanged response: {}", response.body());

            if (response.isSuccessful() && response.body() != null) {
                JSONObject resJson = JSONObject.parseObject(response.body());
                Integer code = resJson.getInteger("code");

                if (code != null && code == 200) {
                    JSONObject data = resJson.getJSONObject("data");
                    int triggeredCount = data != null ? data.getIntValue("triggeredStrategies") : 0;
                    log.debug("属性变化通知成功: obj={}, attr={}, {} -> {}, triggered={}", objCode, attrKey, oldValue,
                        newValue, triggeredCount);
                    return triggeredCount;
                }
                else {
                    log.warn("属性变化通知失败: code={}, msg={}", code, resJson.getString("msg"));
                }
            }
            else {
                log.warn("属性变化通知HTTP失败: status={}, body={}", response.code(), response.body());
            }
        }
        catch (Exception e) {
            log.error("属性变化通知异常: obj={}, attr={}, error={}", objCode, attrKey, e.getMessage());
        }

        return -1;
    }

    /**
     * 批量通知属性值变化（同步）
     *
     * @param objCode    设备代码
     * @param attributes 属性键值对
     * @return 触发的策略数量，失败返回 -1
     */
    public int notifyAttrValueChangedBatch(String objCode, Map<String, Object> attributes) {
        if (!notifyEnabled) {
            log.debug("策略通知已禁用，跳过批量通知: obj={}", objCode);
            return 0;
        }

        if (attributes == null || attributes.isEmpty()) {
            log.debug("属性为空，跳过批量通知: obj={}", objCode);
            return 0;
        }

        try {
            Map<String, Object> request = new HashMap<>();
            request.put("objCode", objCode);
            request.put("attributes", attributes);

            Call<String> call = api.onAttrValueChangedBatch(request);
            Response<String> response = call.execute();

            log.debug("notifyAttrValueChangedBatch response: {}", response.body());

            if (response.isSuccessful() && response.body() != null) {
                JSONObject resJson = JSONObject.parseObject(response.body());
                Integer code = resJson.getInteger("code");

                if (code != null && code == 200) {
                    JSONObject data = resJson.getJSONObject("data");
                    int triggeredCount = data != null ? data.getIntValue("triggeredStrategies") : 0;
                    log.debug("批量属性变化通知成功: obj={}, attrCount={}, triggered={}", objCode, attributes.size(),
                        triggeredCount);
                    return triggeredCount;
                }
                else {
                    log.warn("批量属性变化通知失败: code={}, msg={}", code, resJson.getString("msg"));
                }
            }
            else {
                log.warn("批量属性变化通知HTTP失败: status={}", response.code());
            }
        }
        catch (Exception e) {
            log.error("批量属性变化通知异常: obj={}, error={}", objCode, e.getMessage());
        }

        return -1;
    }

    /**
     * 通知设备事件（同步）
     *
     * @param objCode   设备代码
     * @param eventKey  事件键
     * @param eventData 事件数据（可为null）
     * @return 触发的策略数量，失败返回 -1
     */
    public int notifyDeviceEvent(String objCode, String eventKey, Map<String, Object> eventData) {
        if (!notifyEnabled) {
            log.debug("策略通知已禁用，跳过事件通知: obj={}, event={}", objCode, eventKey);
            return 0;
        }

        try {
            Map<String, Object> data = eventData != null ? eventData : new HashMap<>();

            Call<String> call = api.onDeviceEvent(objCode, eventKey, data);
            Response<String> response = call.execute();

            log.debug("notifyDeviceEvent response: {}", response.body());

            if (response.isSuccessful() && response.body() != null) {
                JSONObject resJson = JSONObject.parseObject(response.body());
                Integer code = resJson.getInteger("code");

                if (code != null && code == 200) {
                    JSONObject respData = resJson.getJSONObject("data");
                    int triggeredCount = respData != null ? respData.getIntValue("triggeredStrategies") : 0;
                    log.debug("设备事件通知成功: obj={}, event={}, triggered={}", objCode, eventKey, triggeredCount);
                    return triggeredCount;
                }
                else {
                    log.warn("设备事件通知失败: code={}, msg={}", code, resJson.getString("msg"));
                }
            }
            else {
                log.warn("设备事件通知HTTP失败: status={}", response.code());
            }
        }
        catch (Exception e) {
            log.error("设备事件通知异常: obj={}, event={}, error={}", objCode, eventKey, e.getMessage());
        }

        return -1;
    }

    /**
     * 获取调度器状态（同步）
     *
     * @return 调度器状态信息，失败返回 null
     */
    public JSONObject getSchedulerStatus() {
        try {
            Call<String> call = api.getSchedulerStatus();
            Response<String> response = call.execute();

            log.debug("getSchedulerStatus response: {}", response.body());

            if (response.isSuccessful() && response.body() != null) {
                JSONObject resJson = JSONObject.parseObject(response.body());
                Integer code = resJson.getInteger("code");

                if (code != null && code == 200) {
                    return resJson.getJSONObject("data");
                }
                else {
                    log.warn("获取调度器状态失败: code={}, msg={}", code, resJson.getString("msg"));
                }
            }
            else {
                log.warn("获取调度器状态HTTP失败: status={}", response.code());
            }
        }
        catch (Exception e) {
            log.error("获取调度器状态异常: error={}", e.getMessage());
        }

        return null;
    }

    /**
     * 重新加载调度器（同步）
     *
     * @return 是否成功
     */
    public boolean reloadScheduler() {
        try {
            Call<String> call = api.reloadScheduler();
            Response<String> response = call.execute();

            log.debug("reloadScheduler response: {}", response.body());

            if (response.isSuccessful() && response.body() != null) {
                JSONObject resJson = JSONObject.parseObject(response.body());
                Integer code = resJson.getInteger("code");
                return code != null && code == 200;
            }
        }
        catch (Exception e) {
            log.error("重新加载调度器异常: error={}", e.getMessage());
        }

        return false;
    }

    // ==================== 异步调用方法 ====================

    /**
     * 通知属性值变化（异步）
     * 不阻塞主流程，适合在数据采集时使用
     *
     * @param objCode  设备代码
     * @param attrKey  属性键
     * @param oldValue 旧值
     * @param newValue 新值
     */
    public void notifyAttrValueChangedAsync(String objCode, String attrKey, Object oldValue, Object newValue) {
        if (!notifyEnabled) {
            return;
        }

        asyncExecutor.submit(() -> {
            try {
                notifyAttrValueChanged(objCode, attrKey, oldValue, newValue);
            }
            catch (Exception e) {
                log.error("异步属性变化通知异常: obj={}, attr={}", objCode, attrKey, e);
            }
        });
    }

    /**
     * 批量通知属性值变化（异步）
     *
     * @param objCode    设备代码
     * @param attributes 属性键值对
     */
    public void notifyAttrValueChangedBatchAsync(String objCode, Map<String, Object> attributes) {
        if (!notifyEnabled || attributes == null || attributes.isEmpty()) {
            return;
        }

        asyncExecutor.submit(() -> {
            try {
                notifyAttrValueChangedBatch(objCode, attributes);
            }
            catch (Exception e) {
                log.error("异步批量属性变化通知异常: obj={}", objCode, e);
            }
        });
    }

    /**
     * 通知设备事件（异步）
     *
     * @param objCode   设备代码
     * @param eventKey  事件键
     * @param eventData 事件数据
     */
    public void notifyDeviceEventAsync(String objCode, String eventKey, Map<String, Object> eventData) {
        if (!notifyEnabled) {
            return;
        }

        asyncExecutor.submit(() -> {
            try {
                notifyDeviceEvent(objCode, eventKey, eventData);
            }
            catch (Exception e) {
                log.error("异步设备事件通知异常: obj={}, event={}", objCode, eventKey, e);
            }
        });
    }
}