package org.dromara.resource.dubbo;

import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.dromara.common.core.utils.DynamicTask;
import org.dromara.resource.api.RemoteSmsService;
import org.dromara.resource.api.domain.RemoteSms;
import org.dromara.resource.config.YsdSmsConfig;
import org.dromara.resource.domain.ZjkSmsConfig;
import org.dromara.resource.mapper.ZjkSmsConfigMapper;
import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.core.factory.SmsFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.annotation.Resource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 短信服务
 *
 * @author Feng
 */
@Slf4j
@RequiredArgsConstructor
@Service
@DubboService
public class RemoteSmsServiceImpl implements RemoteSmsService {
    private static String REGEX_PHONE = "^((13[0-9])|(14[0,1,4-9])|(15[0-3,5-9])|(16[2,5-7])|(17[0-8])|(18[0-9])|(19[0-3,5-9]))\\d{8}$";
    @Resource
    private YsdSmsConfig ysdSmsConfig;
    @Resource
    private ZjkSmsConfigMapper zjkSmsConfigMapper;
    @Resource
    private DynamicTask dynamicTask;


    /**
     * 获取特定供应商类型的 SmsBlend 实例
     *
     * @return SmsBlend 实例，代表指定供应商类型
     */
    private SmsBlend getSmsBlend() {
        // 可自定义厂商配置获取规则 例如根据租户获取 或 负载均衡多个厂商等
        return SmsFactory.getSmsBlend("config1");
    }

    /**
     * 根据给定的 SmsResponse 对象创建并返回一个 RemoteSms 对象，封装短信发送的响应信息
     *
     * @param smsResponse 短信发送的响应信息
     * @return 封装了短信发送结果的 RemoteSms 对象
     */
    private RemoteSms getRemoteSms(SmsResponse smsResponse) {
        // 创建一个 RemoteSms 对象，封装响应信息
        RemoteSms sms = new RemoteSms();
        sms.setSuccess(smsResponse.isSuccess());
        sms.setResponse(smsResponse.getData().toString());
        sms.setConfigId(smsResponse.getConfigId());
        return sms;
    }

    /**
     * 同步方法：发送简单文本短信
     *
     * @param phone   目标手机号
     * @param message 短信内容
     * @return 封装了短信发送结果的 RemoteSms 对象
     */
    @Override
    public RemoteSms sendMessage(String phone, String message) {
        // 调用 getSmsBlend 方法获取对应短信供应商的 SmsBlend 实例
        SmsResponse smsResponse = getSmsBlend().sendMessage(phone, message);
        return getRemoteSms(smsResponse);
    }

    /**
     * 同步方法：发送固定消息模板多模板参数短信
     *
     * @param phone    目标手机号
     * @param messages 短信模板参数，使用 LinkedHashMap 以保持参数顺序
     * @return 封装了短信发送结果的 RemoteSms 对象
     */
    @Override
    public RemoteSms sendMessage(String phone, LinkedHashMap<String, String> messages) {
        SmsResponse smsResponse = getSmsBlend().sendMessage(phone, messages);
        return getRemoteSms(smsResponse);
    }

    /**
     * 同步方法：发送带参数的短信
     *
     * @param phone      目标手机号
     * @param templateId 短信模板ID
     * @param messages   短信模板参数，使用 LinkedHashMap 以保持参数顺序
     * @return 封装了短信发送结果的 RemoteSms 对象
     */
    @Override
    public RemoteSms sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
        // 调用 getSmsBlend 方法获取对应短信供应商的 SmsBlend 实例
        SmsResponse smsResponse = getSmsBlend().sendMessage(phone, templateId, messages);
        return getRemoteSms(smsResponse);
    }

    /**
     * 同步方法：群发简单文本短信
     *
     * @param phones  目标手机号列表
     * @param message 短信内容
     * @return 封装了短信发送结果的 RemoteSms 对象
     */
    @Override
    public RemoteSms messageTexting(List<String> phones, String message) {
        // 调用 getSmsBlend 方法获取对应短信供应商的 SmsBlend 实例
        SmsResponse smsResponse = getSmsBlend().massTexting(phones, message);
        return getRemoteSms(smsResponse);
    }

    /**
     * 同步方法：群发带参数的短信
     *
     * @param phones     目标手机号列表
     * @param templateId 短信模板ID
     * @param messages   短信模板参数，使用 LinkedHashMap 以保持参数顺序
     * @return 封装了短信发送结果的 RemoteSms 对象
     */
    @Override
    public RemoteSms messageTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
        // 调用 getSmsBlend 方法获取对应短信供应商的 SmsBlend 实例
        SmsResponse smsResponse = getSmsBlend().massTexting(phones, templateId, messages);
        return getRemoteSms(smsResponse);
    }

    /**
     * 异步方法：发送简单文本短信
     *
     * @param phone   目标手机号
     * @param message 短信内容
     */
    @Override
    public void sendMessageAsync(String phone, String message) {
        getSmsBlend().sendMessageAsync(phone, message);
    }

    /**
     * 异步方法：发送带参数的短信
     *
     * @param phone      目标手机号
     * @param templateId 短信模板ID
     * @param messages   短信模板参数，使用 LinkedHashMap 以保持参数顺序
     */
    @Override
    public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) {
        getSmsBlend().sendMessageAsync(phone, templateId, messages);
    }

    /**
     * 延迟发送简单文本短信
     *
     * @param phone       目标手机号
     * @param message     短信内容
     * @param delayedTime 延迟发送时间（毫秒）
     */
    @Override
    public void delayMessage(String phone, String message, Long delayedTime) {
        getSmsBlend().delayedMessage(phone, message, delayedTime);
    }

    /**
     * 延迟发送带参数的短信
     *
     * @param phone       目标手机号
     * @param templateId  短信模板ID
     * @param messages    短信模板参数，使用 LinkedHashMap 以保持参数顺序
     * @param delayedTime 延迟发送时间（毫秒）
     */
    @Override
    public void delayMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
        getSmsBlend().delayedMessage(phone, templateId, messages, delayedTime);
    }

    /**
     * 延迟群发简单文本短信
     *
     * @param phones      目标手机号列表
     * @param message     短信内容
     * @param delayedTime 延迟发送时间（毫秒）
     */
    @Override
    public void delayMessageTexting(List<String> phones, String message, Long delayedTime) {
        getSmsBlend().delayMassTexting(phones, message, delayedTime);
    }

    /**
     * 延迟批量发送带参数的短信
     *
     * @param phones      目标手机号列表
     * @param templateId  短信模板ID
     * @param messages    短信模板参数，使用 LinkedHashMap 以保持参数顺序
     * @param delayedTime 延迟发送时间（毫秒）
     */
    @Override
    public void delayMessageTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
        getSmsBlend().delayMassTexting(phones, templateId, messages, delayedTime);
    }

    /**
     * 加入黑名单
     *
     * @param phone 手机号
     */
    @Override
    public void addBlacklist(String phone) {
        getSmsBlend().joinInBlacklist(phone);
    }

    /**
     * 加入黑名单
     *
     * @param phones 手机号列表
     */
    @Override
    public void addBlacklist(List<String> phones) {
        getSmsBlend().batchJoinBlacklist(phones);
    }

    /**
     * 移除黑名单
     *
     * @param phone 手机号
     */
    @Override
    public void removeBlacklist(String phone) {
        getSmsBlend().removeFromBlacklist(phone);
    }

    /**
     * 移除黑名单
     *
     * @param phones 手机号
     */
    @Override
    public void removeBlacklist(List<String> phones) {
        getSmsBlend().batchRemovalFromBlacklist(phones);
    }

    @Override
    public Map<String, String> sendYsdSingleSms(String content, String tel) {
        Map<String, String> res = new HashMap<>();
        String sendStatus = "";
        String errorInfo = "";
        String resultId = null;
        if (regexPhone(tel)) {
            JSONObject jsonObject = smsForYun(tel, content);
            String status = (String) jsonObject.get("status");
            sendStatus = "10".equals(status) ? "1" : "0";
            errorInfo = (String) jsonObject.get("errorCode");
            resultId = jsonObject.getString("resultId");
        } else {
            sendStatus = "0";
            errorInfo = "手机号码格式错误!";
        }
        res.put("status", sendStatus);
        res.put("msg", errorInfo);
        res.put("tel", tel);
        res.put("resultId", resultId);
        return res;

    }

    private String getSendPhones(List<String> phones) {
        final String tml = "<loc:addresses>tel:@</loc:addresses>";
        StringBuffer sb = new StringBuffer();
        if (!CollectionUtils.isEmpty(phones)) {
            for (int i = 0; i < phones.size(); i++) {
                String s = phones.get(i);
                String replace = tml.replace("@", s);
                sb.append(replace);
                if (i < phones.size() - 1) {
                    sb.append("\n");
                }
            }
        }
        return sb.toString();
    }

    public Boolean regexPhone(String phone) {
        int length = 11;
        Boolean b;
        if (phone.length() != length) {
            b = false;
        } else {
            Pattern p = Pattern.compile(REGEX_PHONE);
            Matcher m = p.matcher(phone);
            boolean isMatch = m.matches();
            if (isMatch) {
                b = true;
            } else {
                b = false;
            }
        }
        return b;
    }


    // -------------(2024年12月05日14:21:55) ------------- 新增 云时代短信平台 --------------------------
    public JSONObject smsForYun(String phone, String content) {
        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.add("Expect", "100-continue");
        headers.add("Content-Type", "text/xml; charset=utf-8");
        JSONObject resultObject = new JSONObject();
        ZjkSmsConfig config = zjkSmsConfigMapper.selectSmsConfig();
        String url = config.getSendUrl();

        try {
            // ============== 1. 发送短信 ==============
            String xmlBody = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:v2=\"http://www.huawei.com.cn/schema/common/v2_1\" xmlns:loc=\"http://www.csapi.org/schema/parlayx/sms/send/v2_2/local\">\n" +
                "    <soapenv:Header>\n" +
                "        <v2:RequestSOAPHeader>\n" +
                "            <v2:spId>SP_ID</v2:spId>\n" +
                "            <v2:spPassword>SP_PASSWORD</v2:spPassword>\n" +
                "            <v2:serviceId>SERVICE_ID</v2:serviceId>\n" +
                "        </v2:RequestSOAPHeader>\n" +
                "    </soapenv:Header>\n" +
                "    <soapenv:Body>\n" +
                "        <loc:sendSms>\n" +
                "            <loc:addresses>TEL_</loc:addresses>\n" +
                "            <loc:message>MESSAGE_</loc:message>\n" +
                "            <loc:priority>PRIORITY_</loc:priority>\n" +
                "        </loc:sendSms>\n" +
                "    </soapenv:Body>\n" +
                "</soapenv:Envelope>";
            String body = xmlBody.replace("SP_ID", config.getSpId())
                .replace("SP_PASSWORD", config.getSpPassword())
                .replace("SERVICE_ID", config.getServiceId() == null ? "1" : config.getServiceId())
                .replace("TEL_", "tel:" + phone)
                .replace("MESSAGE_", content)
                .replace("PRIORITY_", "5");
            log.info("发送云时代短信请求报文为: " + body);
            org.springframework.http.HttpEntity<String> requestEntity = new org.springframework.http.HttpEntity<>(body, headers);
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
            String response = responseEntity.getBody();
            String resultId = getSuccessResultId(response);
            log.info("发送云时代短信响应报文为: " + response);
            if (StringUtils.isBlank(resultId)) {
                String errorInfo = getErrorResultId(response);
                resultObject.put("stauts", "9999");
                resultObject.put("errorCode", errorInfo);
                return resultObject;
            }
            //间隔1分钟去获取发短信的状态。
            dynamicTask.startDelay(resultId, () -> getSmsSendStatu(headers, config, url, resultId), 1000 * 60);

            // 组装 返回值
            resultObject.put("resultId", resultId);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return resultObject;
    }

    /**
     * 更新短信发送状态
     *
     * @param headers
     * @param config
     * @param url
     * @param resultId
     */
    private void getSmsSendStatu(HttpHeaders headers, ZjkSmsConfig config, String url, String resultId) {
        RestTemplate restTemplate = new RestTemplate();

        // ============== 2. 根据 resultCode 查询短信发送状态 ==============
        String getSmsStatusBody = "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" +
            "    <SOAP-ENV:Header>\n" +
            "        <v2:RequestSOAPHeader xmlns:v2=\"http://www.huawei.com.cn/schema/common/v2_1\">\n" +
            "            <v2:spId>SP_ID</v2:spId>\n" +
            "            <v2:spPassword>SP_PASSWORD</v2:spPassword>\n" +
            "            <v2:serviceId>SERVICE_ID</v2:serviceId>\n" +
            "        </v2:RequestSOAPHeader>\n" +
            "    </SOAP-ENV:Header>\n" +
            "    <SOAP-ENV:Body>\n" +
            "        <loc:getSmsDeliveryStatus xmlns:loc=\"http://www.csapi.org/schema/parlayx/sms/send/v2_2/local\">\n" +
            "            <loc:smsId>SMS_ID</loc:smsId>\n" +
            "        </loc:getSmsDeliveryStatus>\n" +
            "    </SOAP-ENV:Body>\n" +
            "</SOAP-ENV:Envelope>";
        String smsStatusBody = getSmsStatusBody.replace("SP_ID", config.getSpId())
            .replace("SP_PASSWORD", config.getSpPassword())
            .replace("SERVICE_ID", config.getServiceId() == null ? "1" : config.getServiceId())
            .replace("SMS_ID", resultId);
        log.info("发送云时代短信状态请求报文为: " + smsStatusBody);
        org.springframework.http.HttpEntity<String> requestStatusEntity = new org.springframework.http.HttpEntity<>(smsStatusBody, headers);
        ResponseEntity<String> responseStatusEntity = restTemplate.exchange(url, HttpMethod.POST, requestStatusEntity, String.class);
        String statusResponse = responseStatusEntity.getBody();
        String sendCode = getSmsStatus(statusResponse, resultId);
        Integer sendStatus = 0;
        String sendMsg = null;
        if ("DeliveredToTerminal".equals(sendCode)) {
            sendStatus = 1;
            sendMsg = "交付到终端";
        } else if ("DeliveryImpossible".equals(sendCode)) {
            sendMsg = "交付不可能";

        } else if ("MessageWaiting".equals(sendCode)) {
            sendMsg = "等待消息";

        }
        log.info("发送云时代短信状态响应报文为: " + statusResponse);
        //更新短信发送状态数据
        zjkSmsConfigMapper.updateSmsInfoByResultId(resultId, sendCode, sendStatus, sendMsg);

    }


    // 解析返回的 xml 文件内容 获取发送短信返回的消息id
    public static String getSuccessResultId(String xml) {
        try {
            // 创建 DocumentBuilderFactory 实例
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();

            // 将 XML 字符串转换为 InputStream
            InputStream inputStream = new ByteArrayInputStream(xml.getBytes());

            // 解析 XML
            Document document = builder.parse(inputStream);

            // 获取 Fault 节点
            NodeList faultList = document.getElementsByTagName("ns2:sendSmsResponse");
            if (faultList.getLength() > 0) {
                Node faultNode = faultList.item(0);

                if (faultNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element faultElement = (Element) faultNode;

                    // 获取 result
                    String result = faultElement.getElementsByTagName("ns2:result").item(0).getTextContent();
                    return result;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public String getErrorResultId(String xml) {
        try {
            // 创建 DocumentBuilderFactory 实例
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();

            // 将 XML 字符串转换为 InputStream
            InputStream inputStream = new ByteArrayInputStream(xml.getBytes());

            // 解析 XML
            Document document = builder.parse(inputStream);

            // 获取 Fault 节点
            NodeList faultList = document.getElementsByTagName("soap:Fault");
            if (faultList.getLength() > 0) {
                Node faultNode = faultList.item(0);

                if (faultNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element faultElement = (Element) faultNode;

                    // 获取 faultcode 和 faultstring
                    String faultCode = faultElement.getElementsByTagName("faultcode").item(0).getTextContent();
                    String faultString = faultElement.getElementsByTagName("faultstring").item(0).getTextContent();
                    return faultString;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取 短信返回状态
     *
     * @param xml
     * @param smsIdValue
     * @return
     */
    public String getSmsStatus(String xml, String smsIdValue) {
        String status = null;

        try {
            // 创建 DocumentBuilderFactory 实例
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();

            // 将 XML 字符串转换为 InputStream
            InputStream inputStream = new ByteArrayInputStream(xml.getBytes());

            // 解析 XML
            Document document = builder.parse(inputStream);

            // 获取所有 deliveryStatus 元素
            NodeList deliveryStatusList = document.getElementsByTagName("deliveryStatus");

            for (int i = 0; i < deliveryStatusList.getLength(); i++) {
                Node node = deliveryStatusList.item(i);

                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    Element element = (Element) node;

                    // 获取 smsId 元素并检查它是否等于目标值
                    String smsId = getElementTextContent(element, "smsId");
                    if (smsId != null && smsId.equals(smsIdValue)) {
                        // 获取 status 元素的值
                        status = getElementTextContent(element, "status");
                        break; // 找到目标 smsId 后退出循环
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return status;
    }

    // 辅助方法：获取元素的文本内容
    private String getElementTextContent(Element element, String tagName) {
        NodeList nodeList = element.getElementsByTagName(tagName);
        if (nodeList.getLength() > 0) {
            return nodeList.item(0).getTextContent();
        }
        return null;
    }

    public static void main(String[] args) {
        String cc = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><ns2:sendSmsResponse xmlns:ns2=\"http://www.csapi.org/schema/parlayx/sms/send/v2_2/local\" xmlns:ns3=\"http://www.csapi.org/schema/parlayx/common/v2_1\"><ns2:result>251225151045162409</ns2:result></ns2:sendSmsResponse></soap:Body></soap:Envelope>";
        String successResultId = getSuccessResultId(cc);
        System.out.println(successResultId);

    }
}
