/*
 * 文 件 名:  Acrel3000Template
 * 版    权:  华设设计集团股份有限公司
 * 描    述:  <描述>
 * 修 改 人:  lvwenbin
 * 修改时间:  2025/7/19
 * 跟踪单号:  <跟踪单号>
 * 修改单号:  <修改单号>
 * 修改内容:  <修改内容>
 */
package com.ruoyi.ems.core;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.retrofit.Retrofit2ConverterFactory;
import com.huashe.common.exception.Assert;
import com.huashe.common.utils.DateUtils;
import com.ruoyi.common.core.utils.SpringUtils;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.ems.config.AcrelConfig;
import com.ruoyi.ems.model.acrel.AlarmEventLog;
import com.ruoyi.ems.model.acrel.Circuit;
import com.ruoyi.ems.model.acrel.ConsumeReport;
import com.ruoyi.ems.model.acrel.MeterKeyValue;
import com.ruoyi.ems.model.acrel.MeterUse;
import com.ruoyi.ems.model.acrel.Station;
import com.ruoyi.ems.model.acrel.Token;
import com.ruoyi.ems.retrofit.Acrel3000Api;
import lombok.extern.slf4j.Slf4j;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import org.apache.commons.lang3.StringUtils;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 安科瑞3000系列模板类
 * <功能详细描述>
 *
 * @author lvwenbin
 * @version [版本号, 2025/7/19]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Slf4j
public class Acrel3000Template extends BaseApiTemplate {
    /**
     * 访问地址
     */
    protected String url;

    /**
     * 调用代理
     */
    protected final Acrel3000Api api;

    public Acrel3000Template(String restUrl) {
        this.url = restUrl;

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

    /**
     * 构造调用模板
     *
     * @param restUrl        服务地址 (http://ip:port)
     * @param connectTimeout 连接超时
     * @param readTimeout    读取超时
     * @param writeTimeout   写超时
     */
    public Acrel3000Template(String restUrl, int connectTimeout, int readTimeout, int writeTimeout) {
        super.connectTimeout = connectTimeout;
        super.readTimeout = readTimeout;
        super.writeTimeout = writeTimeout;
        this.url = restUrl;

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

    public synchronized String getAuthToken() {
        RedisService redisService = SpringUtils.getBean(RedisService.class);
        String tokenStr = redisService.getCacheObject("ACREL_AUTH_TOKEN");

        if (StringUtils.isEmpty(tokenStr)) {
            AcrelConfig config = SpringUtils.getBean(AcrelConfig.class);
            Token token = getAuthToken(config.getAuthLoginName(), config.getAuthPassword());
            Assert.notNull(token, -1, "获取权限失败");

            Date expireDate = DateUtils.stringToDate(token.getExpireDate(), "yyyy-MM-dd HH:mm:ss");
            Date currentDate = new Date();
            long expireSeconds = (expireDate.getTime() - currentDate.getTime()) / 1000;
            Assert.isTrue(expireSeconds > 0, -1, "Token已过期或过期时间无效");
            redisService.setCacheObject("ACREL_AUTH_TOKEN", token.getToken(), expireSeconds, TimeUnit.SECONDS);
            tokenStr = token.getToken();
        }

        return tokenStr;
    }

    /**
     * 获取权限
     *
     * @param loginName 用户名
     * @param password  密码
     * @return 响应
     */
    public Token getAuthToken(String loginName, String password) {
        Token token = null;

        try {
            // 创建请求体
            RequestBody loginnameBody = RequestBody.create(MediaType.parse("text/plain"), loginName);
            RequestBody passwordBody = RequestBody.create(MediaType.parse("text/plain"), password);

            // 执行调用
            Call<String> call = api.getAuthToken(loginnameBody, passwordBody);
            Response<String> response = call.execute();
            log.debug("getAuthToken response:{}", response);

            JSONObject resJson = JSONObject.parseObject(response.body());
            Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
                resJson.getString("msg"));

            String dataStr = resJson.getString("data");
            token = JSONObject.parseObject(dataStr, Token.class);
        }
        catch (Exception e) {
            log.error("getAuthToken fail!", e);
        }

        return token;
    }

    /**
     * 获取站点列表
     *
     * @param coacCountNo 企业编号(和站点区域分组id不能同时存在)
     * @param subGroupId  站点区域分组编号(和企业编号不能同时存在)
     * @return 响应
     */
    public List<Station> getStationTreeList(String coacCountNo, String subGroupId) {
        List<Station> stations = null;

        try {
            // 动态构建参数字段
            Map<String, RequestBody> fields = new HashMap<>();
            fields.put("type", RequestBody.create(MediaType.parse("text/plain"), "0"));

            if (StringUtils.isNotBlank(coacCountNo)) {
                fields.put("fCoaccountno", RequestBody.create(MediaType.parse("text/plain"), coacCountNo));
            }

            if (StringUtils.isNotBlank(subGroupId)) {
                fields.put("fSubgroupid", RequestBody.create(MediaType.parse("text/plain"), subGroupId));
            }

            // 执行调用
            Call<String> call = api.getStationTreeList(getAuthToken(), fields);
            Response<String> response = call.execute();
            log.debug("getStationTreeList response:{}", response.body());

            JSONObject resJson = JSONObject.parseObject(response.body());
            Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
                resJson.getString("msg"));

            JSONObject dataJson = resJson.getJSONObject("data");
            int num = dataJson.getInteger("num");

            if (num > 0) {
                String list = dataJson.getString("list");
                stations = JSONObject.parseArray(list, Station.class);
            }
            else {
                stations = new ArrayList<>();
            }
        }
        catch (Exception e) {
            log.error("getStationTreeList fail!", e);
        }

        return stations;
    }

    /**
     * 获取仪表列表
     *
     * @param subId 站点ID
     * @return 响应
     */
    public List<MeterUse> getMeterUseInfoList(String subId) {
        List<MeterUse> list = new ArrayList<>();

        try {
            int pageNo = 1;
            int pageSize = 20;
            int english = 0;
            boolean isLastPage;

            do {
                // 执行调用
                Call<String> call = api.getMeterUseInfoList(getAuthToken(), subId, pageNo, pageSize, english);
                Response<String> response = call.execute();
                log.debug("getMeterUseInfoList response:{}", response);

                JSONObject resJson = JSONObject.parseObject(response.body());
                Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
                    resJson.getString("msg"));

                JSONObject dataJson = resJson.getJSONObject("data");
                isLastPage = dataJson.getBoolean("isLastPage");
                String listStr = dataJson.getString("list");
                list.addAll(JSONObject.parseArray(listStr, MeterUse.class));

                pageNo++;
            }
            while (!isLastPage);
        }
        catch (Exception e) {
            log.error("getMeterUseInfoList fail!", e);
        }

        return list;
    }

    /**
     * 获取回路列表
     *
     * @param subId 站点ID
     * @return 响应
     */
    public List<Circuit> getCircuitInfoTree(String subId) {
        List<Circuit> circuitList = null;

        try {
            // 执行调用
            Call<String> call = api.getCircuitInfoTree(getAuthToken(), subId);
            Response<String> response = call.execute();
            log.debug("getCircuitInfoTree response:{}", response);

            JSONObject resJson = JSONObject.parseObject(response.body());
            Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
                resJson.getString("msg"));

            String dataStr = resJson.getString("data");
            circuitList = JSONObject.parseArray(dataStr, Circuit.class);
        }
        catch (Exception e) {
            log.error("getCircuitInfoTree fail!", e);
        }

        return circuitList;
    }

    /**
     * 获取实时数据
     *
     * @param subId     站点ID
     * @param meterCode 设备ID
     * @return 响应
     */
    public List<MeterKeyValue> getMeterParamValueByKey(String subId, String meterCode) {
        List<MeterKeyValue> meterKvList = null;

        try {
            // 执行调用
            Call<String> call = api.getMeterParamValueByKey(getAuthToken(), subId, meterCode);
            Response<String> response = call.execute();
            log.debug("getMeterParamValueByKey response:{}", response);

            JSONObject resJson = JSONObject.parseObject(response.body());
            Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
                resJson.getString("msg"));

            JSONObject dataJson = resJson.getJSONObject("data");
            Assert.notNull(dataJson, -1, "data is null!");

            String resultStr = dataJson.getString("result");
            meterKvList = JSONObject.parseArray(resultStr, MeterKeyValue.class);
        }
        catch (Exception e) {
            log.error("getMeterParamValueByKey fail!", e);
        }

        return meterKvList;
    }

    /**
     * 用能集抄
     *
     * @param circuitIds 回路ID集合
     * @param type       类型 min：分， hour: 时， day: 日， mon: 月
     * @return 响应
     */
    public ConsumeReport getNewConsumeReport(String circuitIds, String type, String startTime, String endTime,
        String interval, String paramCode) {
        ConsumeReport consumeReport = null;

        try {
            // 动态构建参数字段
            Map<String, RequestBody> fields = new HashMap<>();
            fields.put("fCircuitids", RequestBody.create(MediaType.parse("text/plain"), circuitIds));
            fields.put("type", RequestBody.create(MediaType.parse("text/plain"), type));
            fields.put("startTime", RequestBody.create(MediaType.parse("text/plain"), startTime));
            fields.put("endTime", RequestBody.create(MediaType.parse("text/plain"), endTime));
            fields.put("interval", RequestBody.create(MediaType.parse("text/plain"), interval));
            fields.put("paramCode", RequestBody.create(MediaType.parse("text/plain"), paramCode));

            // 执行调用
            Call<String> call = api.getNewConsumeReport(getAuthToken(), fields);
            Response<String> response = call.execute();
            log.debug("getNewConsumeReport response:{}", response);

            JSONObject resJson = JSONObject.parseObject(response.body());
            Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
                resJson.getString("msg"));

            String dataStr = resJson.getString("data");
            consumeReport = JSONObject.parseObject(dataStr, ConsumeReport.class);
        }
        catch (Exception e) {
            log.error("getNewConsumeReport fail!", e);
        }

        return consumeReport;
    }

    /**
     * 获取报警事件列表
     * @param subId 站点ID
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 响应
     */
    public List<AlarmEventLog> getAlarmEventLogList(String subId, String startTime, String endTime) {
        List<AlarmEventLog> list = new ArrayList<>();

        try {
            int pageNo = 1;
            int pageSize = 20;
            boolean isLastPage;

            do {
                // 动态构建参数字段
                Map<String, RequestBody> fields = new HashMap<>();

                if (null != subId) {
                    fields.put("subId", RequestBody.create(MediaType.parse("text/plain"), subId));
                }

                fields.put("startTime", RequestBody.create(MediaType.parse("text/plain"), startTime));
                fields.put("endTime", RequestBody.create(MediaType.parse("text/plain"), endTime));
                fields.put("pageNo", RequestBody.create(MediaType.parse("text/plain"), String.valueOf(pageNo)));
                fields.put("pageSize", RequestBody.create(MediaType.parse("text/plain"), String.valueOf(pageSize)));

                // 执行调用
                Call<String> call = api.getAlarmEventLogList(getAuthToken(), fields);
                Response<String> response = call.execute();
                log.debug("getAlarmEventLogList response:{}", response);

                JSONObject resJson = JSONObject.parseObject(response.body());
                Assert.isTrue(StringUtils.equals(resJson.getString("code"), "200"), resJson.getInteger("code"),
                    resJson.getString("msg"));

                JSONObject dataJson = resJson.getJSONObject("data");
                Assert.notNull(dataJson, -1, "data is null!");
                JSONObject alarmJson = dataJson.getJSONObject("alarmEventLogList");

                isLastPage = alarmJson.getBoolean("isLastPage");
                String listStr = alarmJson.getString("list");
                List<AlarmEventLog> tmp = JSONObject.parseArray(listStr, AlarmEventLog.class);

                list.addAll(tmp);

                fields.clear();
                pageNo++;
            }
            while (!isLastPage);
        }
        catch (Exception e) {
            log.error("getAlarmEventLogList fail!", e);
        }

        return list;
    }
}