package com.zksy.api.utils;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.auth.credentials.Credential;
import com.aliyun.auth.credentials.provider.StaticCredentialProvider;
import com.aliyun.sdk.service.dysmsapi20170525.AsyncClient;
import com.aliyun.sdk.service.dysmsapi20170525.models.SendBatchSmsRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.SendBatchSmsResponse;
import com.google.gson.Gson;
import com.zksy.api.config.AliyunSmsConfig;
import com.zksy.api.domain.AlarmData;
import com.zksy.api.domain.WarningThreshold;
import com.zksy.api.service.AlarmDataService;
import com.zksy.api.service.WarningThresholdService;
import darabonba.core.client.ClientOverrideConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import rk.netDevice.sdk.p2.NodeData;
import rk.netDevice.sdk.p2.RealTimeData;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Component
@Slf4j
public class SmsUtil {

    private final AliyunSmsConfig aliyunSmsConfig;
    private final AsyncClient client;

    private final WarningThresholdService service;
    private final AlarmDataService alarmDataService;

    // 报警缓存和冷却时间
//    private static final Map<String, Long> ALARM_CACHE = new ConcurrentHashMap<>();
//    private static final long ALARM_COOLDOWN_MS = 5 * 60 * 1000;

    @Autowired
    public SmsUtil(AliyunSmsConfig aliyunSmsConfig, WarningThresholdService service, AlarmDataService alarmDataService) {
        this.aliyunSmsConfig = aliyunSmsConfig;
        this.service = service;
        this.alarmDataService = alarmDataService;

        try {
            StaticCredentialProvider provider = StaticCredentialProvider.create(Credential.builder()
                    .accessKeyId(aliyunSmsConfig.getAccessKeyId())
                    .accessKeySecret(aliyunSmsConfig.getAccessKeySecret())
                    .build());

            this.client = AsyncClient.builder()
                    .region(aliyunSmsConfig.getRegionId())
                    .credentialsProvider(provider)
                    .overrideConfiguration(
                            ClientOverrideConfiguration.create()
                                    .setEndpointOverride("dysmsapi.aliyuncs.com")
                                    .setConnectTimeout(Duration.ofSeconds(30))
                    )
                    .build();
        } catch (Exception e) {
            log.error("阿里云短信客户端初始化失败", e);
            throw new RuntimeException("短信服务初始化异常", e); // 初始化失败应快速失败
        }
    }
    /**
     * 批量发送相同内容的短信给多个手机号（使用默认报警模板）
     * @param phoneNumbers 接收短信的手机号列表
     * @param templateParam 短信模板参数，JSON格式字符串
     * @return 发送结果，key为手机号，value为是否成功
     */
    public Map<String, Boolean> sendBatchSms(List<String> phoneNumbers, String templateParam) {
        return sendBatchSms(phoneNumbers, templateParam, aliyunSmsConfig.getTemplateCode());
    }

    /**
     * 批量发送相同内容的短信给多个手机号（可指定模板编码）
     * @param phoneNumbers 接收短信的手机号列表
     * @param templateParam 短信模板参数，JSON格式字符串
     * @param templateCode 短信模板编码
     * @return 发送结果，key为手机号，value为是否成功
     */
    public Map<String, Boolean> sendBatchSms(List<String> phoneNumbers, String templateParam, String templateCode) {
        if (phoneNumbers == null || phoneNumbers.isEmpty()) {
            log.warn("批量发送短信失败：手机号列表为空");
            return Collections.emptyMap();
        }
        if (templateCode == null || templateCode.trim().isEmpty()) {
            log.warn("批量发送短信失败：模板编码为空");
            return phoneNumbers.stream().collect(Collectors.toMap(p -> p, p -> false));
        }

        try {
            List<String> signNames = phoneNumbers.stream()
                    .map(phone -> aliyunSmsConfig.getSignName())
                    .collect(Collectors.toList());

            List<String> templateParams = phoneNumbers.stream()
                    .map(phone -> templateParam)
                    .collect(Collectors.toList());

            SendBatchSmsRequest request = SendBatchSmsRequest.builder()
                    .phoneNumberJson(new Gson().toJson(phoneNumbers))
                    .signNameJson(new Gson().toJson(signNames))
                    .templateCode(templateCode)
                    .templateParamJson(new Gson().toJson(templateParams))
                    .build();

            CompletableFuture<SendBatchSmsResponse> response = client.sendBatchSms(request);
            SendBatchSmsResponse resp = response.get();

            log.info("批量短信发送响应: templateCode={}, resp={}", templateCode, new Gson().toJson(resp.getBody()));
            return phoneNumbers.stream()
                    .collect(Collectors.toMap(
                            phone -> phone,
                            phone -> "OK".equals(resp.getBody().getCode())
                    ));
        } catch (Exception e) {
            log.error("批量短信发送失败: templateCode={}, error={}", templateCode, e.getMessage());
            e.printStackTrace();
            return phoneNumbers.stream()
                    .collect(Collectors.toMap(
                            phone -> phone,
                            phone -> false
                    ));
        }
    }

    /**
     * 发送维修派单通知短信
     * @param phoneNumbers 接收短信的手机号列表
     * @param deviceName 设备名称
     * @param deviceNo 设备编号
     * @param location 设备位置
     * @param faultDesc 故障描述
     * @return 发送结果，key为手机号，value为是否成功
     */
    public Map<String, Boolean> sendMaintainNotify(List<String> phoneNumbers,
                                                    String deviceName, String deviceNo,
                                                    String location, String faultDesc) {
        String maintainTemplateCode = aliyunSmsConfig.getMaintainTemplateCode();
        if (maintainTemplateCode == null || maintainTemplateCode.trim().isEmpty()) {
            log.warn("维修派单短信模板未配置（aliyun.sms.maintain-template-code），跳过发送");
            return phoneNumbers != null
                    ? phoneNumbers.stream().collect(Collectors.toMap(p -> p, p -> false))
                    : Collections.emptyMap();
        }

        JSONObject params = new JSONObject();
        params.put("deviceName", deviceName != null ? deviceName : "未知设备");
        params.put("deviceNo", deviceNo != null ? deviceNo : "无");
        params.put("location", location != null && !location.isEmpty() ? location : "暂无位置信息");
        params.put("faultDesc", faultDesc != null && !faultDesc.isEmpty() ? faultDesc : "请查看工单详情");

        return sendBatchSms(phoneNumbers, params.toJSONString(), maintainTemplateCode);
    }

    /**
     * 检查设备数据是否触发报警并发送短信
     */
    public boolean checkDeviceAlarmAndSend(RealTimeData realTimeData, NodeData nodeData, List<String> alarmPhones) {

        if (realTimeData == null || nodeData == null) {
            log.error("预警参数异常：设备数据或节点数据为空");
            return false;
        }
        if (realTimeData.getDeviceId() <= 0) {
            log.error("预警参数异常：设备ID无效（{}）", realTimeData.getDeviceId());
            return false;
        }

        int nodeId = nodeData.getNodeId();
        if (nodeId < 1 || nodeId > 5) {
            log.error("节点ID无效（{}），仅支持1-5的节点", nodeId);
            return false;
        }

        try {
            //TODO 冷处理待定
//            String cacheKey = realTimeData.getDeviceId() + "_" + nodeId;
//            Long lastAlarmTime = ALARM_CACHE.get(cacheKey);
//            if (lastAlarmTime != null && System.currentTimeMillis() - lastAlarmTime < ALARM_COOLDOWN_MS) {
//                log.info("设备{}节点{}在冷却时间内，暂不重复报警", realTimeData.getDeviceId(), nodeId);
//                return false;
//            }

            // 根据node_id获取预警编码（自定义写死，不从枚举获取）
            String warningCode = getWarningCodeByNodeId(nodeId);
            if (warningCode == null) {
                log.warn("设备{}节点{}无对应预警编码，跳过检查", realTimeData.getDeviceId(), nodeId);
                return false;
            }

            // 设备编号从设备数据获取
            String deviceCode = String.valueOf(realTimeData.getDeviceId());

            // 查询预警阈值表
            WarningThreshold threshold = null;
            try {
                threshold = service.getWarningThresholdByDeviceAndCode(deviceCode, warningCode);
            } catch (Exception e) {
                log.error("查询预警阈值失败", e);
            }

            // 获取预警类型，默认使用节点对应的名称
            String warningType = getWarningTypeNameByNodeId(nodeId);
            if (threshold != null && threshold.getWarningType() != null) {
                warningType = threshold.getWarningType();
            }

            // 获取最小值和最大值
            Double minValue = threshold != null ? threshold.getMinValue() : null;
            Double maxValue = threshold != null ? threshold.getMaxValue() : null;
            String remark = threshold != null ? threshold.getRemark() : null;

            // 获取当前节点的指标数值
            double currentValue = getCurrentValueByNodeId(nodeData, nodeId);

            // 判断是否触发报警
            boolean isOverThreshold = false;
            if (minValue != null && currentValue <= minValue) {
                isOverThreshold = true;
            }
            if (maxValue != null && currentValue >= maxValue) {
                isOverThreshold = true;
            }

            log.debug("设备{}节点{} - 预警类型：{}，当前值：{}，最小值：{}，最大值：{}，是否超限：{}",
                    realTimeData.getDeviceId(), nodeId, warningType, currentValue, minValue, maxValue, isOverThreshold);

            // 触发报警
            if (isOverThreshold) {
                log.warn("设备{}节点{}触发预警：{}（当前值：{}，最小值：{}，最大值：{}）",
                        realTimeData.getDeviceId(), nodeId, warningType, currentValue, minValue, maxValue);

                // 1. 先保存 alarm_data
                saveAlarmData(deviceCode, warningType, warningCode,
                        minValue != null ? BigDecimal.valueOf(minValue) : null,
                        maxValue != null ? BigDecimal.valueOf(maxValue) : null,
                        BigDecimal.valueOf(currentValue), remark);

                // 2. 再构造并发送短信
                JSONObject params = new JSONObject();
                params.put("deviceNo", realTimeData.getDeviceId());
                params.put("alarmType", warningType);
                double lng = nodeData.getLng();
                double lat = nodeData.getLat();
                params.put("location", String.format("经纬度：%.6f,%.8f", lng, lat));

                Map<String, Boolean> sendResults = this.sendBatchSms(alarmPhones, params.toJSONString());
                long successCount = sendResults.values().stream().filter(Boolean::booleanValue).count();
                log.info("设备{}报警短信发送完成，成功{}条，失败{}条",
                        realTimeData.getDeviceId(), successCount, sendResults.size() - successCount);

                // 冷却处理
                // ALARM_CACHE.put(cacheKey, System.currentTimeMillis());
                return true;
            }
            return false;
        } catch (Exception e) {
            log.error("设备{}节点{}报警处理失败", realTimeData.getDeviceId(), nodeId, e);
            return false;
        }
    }

    /**
     * 保存告警数据到 alarm_data 表
     */
    private void saveAlarmData(String deviceCode, String warningType, String warningCode,
                               BigDecimal minValue, BigDecimal maxValue, BigDecimal actualValue, String remark) {
        try {
            AlarmData alarmData = new AlarmData();
            alarmData.setDeviceCode(deviceCode);
            alarmData.setWarningType(warningType);
            alarmData.setWarningCode(warningCode);
            alarmData.setMinValue(minValue);
            alarmData.setMaxValue(maxValue);
            alarmData.setActualValue(actualValue);
            alarmData.setAlarmStatus(0);
            alarmData.setAlarmTime(LocalDateTime.now());
            alarmData.setRemark(remark);
            alarmData.setCreateTime(LocalDateTime.now());
            alarmDataService.saveAlarmData(alarmData);
        } catch (Exception e) {
            log.error("保存告警数据失败", e);
        }
    }

    /**
     * 根据nodeId获取对应的预警编码（自定义写死）
     */
    private String getWarningCodeByNodeId(int nodeId) {
        switch (nodeId) {
            case 1: return "WARN_SUSPENDED_SOLIDS";
            case 2: return "WARN_COD";
            case 3: return "WARN_AMMONIA_NITROGEN";
            case 4: return "WARN_CONDUCTIVITY";
            case 5: return "WARN_PH";
            default: return null;
        }
    }

    /**
     * 根据nodeId获取对应的预警类型名称
     */
    private String getWarningTypeNameByNodeId(int nodeId) {
        switch (nodeId) {
            case 1: return "悬浮物";
            case 2: return "COD";
            case 3: return "氨氮";
            case 4: return "电导率";
            case 5: return "pH值";
            default: return "未知预警";
        }
    }

    /**
     * 根据nodeId获取对应的指标数值
     */
    private double getCurrentValueByNodeId(NodeData nodeData, int nodeId) {
        if (nodeId == 1) {
            // 节点1需要特殊处理，取悬浮物字段（floatValue字段）
            return nodeData.getFloatValue();
        } else {
            // 其他节点取hum字段
            return nodeData.getHum();
        }
    }
}
