package com.writeoff.module.notification.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.writeoff.common.exception.BusinessException;
import com.writeoff.module.notification.dto.TestPlatformNotifyGatewayRequest;
import com.writeoff.module.notification.model.PlatformNotifyGatewayResolvedConfig;
import com.writeoff.module.notification.provider.SmsNotificationProvider;
import com.writeoff.module.notification.provider.NotificationSendResult;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.stereotype.Service;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

@Service
public class PlatformNotifyGatewayTestService {
    private final PlatformNotifyGatewayService gatewayService;
    private final SmsNotificationProvider smsNotificationProvider;
    private final ObjectMapper objectMapper = new ObjectMapper();

    public PlatformNotifyGatewayTestService(PlatformNotifyGatewayService gatewayService,
                                            SmsNotificationProvider smsNotificationProvider) {
        this.gatewayService = gatewayService;
        this.smsNotificationProvider = smsNotificationProvider;
    }

    public Map<String, Object> test(String channelCode, TestPlatformNotifyGatewayRequest request) {
        PlatformNotifyGatewayResolvedConfig gateway = gatewayService.resolveChannelConfig(channelCode, false);
        if (gateway == null) {
            throw new BusinessException(10003, "通知网关不存在");
        }
        if ("EMAIL".equalsIgnoreCase(gateway.getChannelCode())) {
            return testEmail(gateway, request);
        }
        if ("SMS".equalsIgnoreCase(gateway.getChannelCode())) {
            return testSms(gateway, request);
        }
        throw new BusinessException(10001, "暂不支持的通知网关测试渠道");
    }

    private Map<String, Object> testEmail(PlatformNotifyGatewayResolvedConfig gateway, TestPlatformNotifyGatewayRequest request) {
        Map<String, Object> config = gateway.getConfig();
        String host = text(config.get("host"));
        String fromAddress = text(config.get("fromAddress"));
        boolean smtpAuth = boolValue(config.get("smtpAuth"), true);
        String username = text(config.get("username"));
        String password = text(config.get("password"));
        if (host.isEmpty()) {
            throw new BusinessException(10001, "SMTP 主机不能为空");
        }
        if (fromAddress.isEmpty()) {
            throw new BusinessException(10001, "发件邮箱不能为空");
        }
        if (smtpAuth) {
            if (username.isEmpty()) {
                throw new BusinessException(10001, "SMTP 用户名不能为空");
            }
            if (password.isEmpty()) {
                throw new BusinessException(10001, "SMTP 密码不能为空");
            }
        }
        try {
            JavaMailSenderImpl sender = new JavaMailSenderImpl();
            sender.setHost(host);
            sender.setPort(intValue(config.get("port"), 587));
            sender.setProtocol(textOr(config.get("protocol"), "smtp"));
            sender.setUsername(username);
            sender.setPassword(password);
            Properties props = sender.getJavaMailProperties();
            props.put("mail.smtp.auth", String.valueOf(smtpAuth));
            props.put("mail.smtp.starttls.enable", String.valueOf(boolValue(config.get("starttlsEnable"), true)));
            props.put("mail.smtp.starttls.required", String.valueOf(boolValue(config.get("starttlsRequired"), false)));
            props.put("mail.smtp.ssl.enable", String.valueOf(boolValue(config.get("sslEnable"), false)));
            props.put("mail.smtp.connectiontimeout", String.valueOf(intValue(config.get("connectTimeoutMs"), 5000)));
            props.put("mail.smtp.timeout", String.valueOf(intValue(config.get("timeoutMs"), 5000)));
            props.put("mail.smtp.writetimeout", String.valueOf(intValue(config.get("writeTimeoutMs"), 5000)));

            SimpleMailMessage message = new SimpleMailMessage();
            message.setFrom(fromAddress);
            message.setTo(request.getReceiverRef().trim());
            message.setSubject(textOr(request.getSubject(), "通知网关测试"));
            message.setText(textOr(request.getContent(), "这是一封来自平台通知网关配置中心的测试邮件。"));
            sender.send(message);

            Map<String, Object> data = new LinkedHashMap<String, Object>();
            data.put("channelCode", gateway.getChannelCode());
            data.put("providerCode", gateway.getProviderCode());
            data.put("receiverRef", request.getReceiverRef().trim());
            data.put("accepted", Boolean.TRUE);
            data.put("message", "测试邮件发送成功");
            return data;
        } catch (Exception ex) {
            throw new BusinessException(10001, "测试邮件发送失败: " + ex.getMessage());
        }
    }

    private Map<String, Object> testSms(PlatformNotifyGatewayResolvedConfig gateway, TestPlatformNotifyGatewayRequest request) {
        Map<String, Object> config = gateway.getConfig();
        boolean mockEnabled = boolValue(config.get("mockEnabled"), "MOCK".equalsIgnoreCase(gateway.getProviderCode()));
        if (!mockEnabled) {
            if (text(config.get("endpoint")).isEmpty()) {
                throw new BusinessException(10001, "短信服务地址不能为空");
            }
            if (text(config.get("signName")).isEmpty()) {
                throw new BusinessException(10001, "短信签名不能为空");
            }
            if (text(config.get("accessKeyId")).isEmpty()) {
                throw new BusinessException(10001, "短信 AccessKeyId 不能为空");
            }
            if (text(config.get("accessKeySecret")).isEmpty()) {
                throw new BusinessException(10001, "短信 AccessKeySecret 不能为空");
            }
        }
        if (!isPhoneLike(request.getReceiverRef())) {
            throw new BusinessException(10001, "短信测试接收目标必须为手机号");
        }
        Map<String, Object> payload = new LinkedHashMap<String, Object>();
        payload.put("subject", textOr(request.getSubject(), "通知网关测试"));
        payload.put("content", textOr(request.getContent(), "这是一条来自平台通知网关配置中心的测试短信。"));
        payload.put("signName", text(config.get("signName")));
        payload.put("templateCode", text(config.get("templateCode")));
        try {
            if ("ALIYUN_SMS".equalsIgnoreCase(gateway.getProviderCode()) && !mockEnabled) {
                Map<String, Object> sendContext = new LinkedHashMap<String, Object>();
                sendContext.put("outId", "test-" + System.currentTimeMillis());
                NotificationSendResult result = smsNotificationProvider.send(
                        request.getReceiverRef().trim(),
                        objectMapper.writeValueAsString(payload),
                        sendContext
                );
                if (result == null || !result.isAccepted()) {
                    throw new BusinessException(10001, result == null ? "测试短信发送失败" : result.getProviderMessage());
                }
                Map<String, Object> data = new LinkedHashMap<String, Object>();
                data.put("channelCode", gateway.getChannelCode());
                data.put("providerCode", gateway.getProviderCode());
                data.put("receiverRef", request.getReceiverRef().trim());
                data.put("accepted", Boolean.TRUE);
                data.put("providerMessageId", result.getProviderMessageId());
                data.put("providerResultCode", result.getProviderCode());
                data.put("message", result.getProviderMessage());
                return data;
            }
            Map<String, Object> data = new LinkedHashMap<String, Object>();
            data.put("channelCode", gateway.getChannelCode());
            data.put("providerCode", gateway.getProviderCode());
            data.put("receiverRef", request.getReceiverRef().trim());
            data.put("accepted", Boolean.TRUE);
            data.put("mockEnabled", mockEnabled);
            data.put("payloadJson", objectMapper.writeValueAsString(payload));
            data.put("message", mockEnabled ? "测试短信已模拟受理" : "测试短信参数校验通过，当前版本按模拟模式返回受理");
            return data;
        } catch (Exception ex) {
            throw new BusinessException(10001, "测试短信构造失败");
        }
    }

    private boolean isPhoneLike(String value) {
        String normalized = text(value);
        if (normalized.startsWith("+")) {
            normalized = normalized.substring(1);
        }
        if (normalized.length() < 6 || normalized.length() > 20) {
            return false;
        }
        for (int i = 0; i < normalized.length(); i++) {
            if (!Character.isDigit(normalized.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    private String text(Object value) {
        return value == null ? "" : String.valueOf(value).trim();
    }

    private String textOr(Object value, String fallback) {
        String text = text(value);
        return text.isEmpty() ? fallback : text;
    }

    private int intValue(Object value, int fallback) {
        if (value == null) {
            return fallback;
        }
        try {
            return value instanceof Number ? ((Number) value).intValue() : Integer.parseInt(String.valueOf(value).trim());
        } catch (Exception ex) {
            return fallback;
        }
    }

    private boolean boolValue(Object value, boolean fallback) {
        if (value == null) {
            return fallback;
        }
        if (value instanceof Boolean) {
            return (Boolean) value;
        }
        String text = String.valueOf(value).trim();
        if ("true".equalsIgnoreCase(text) || "1".equals(text)) {
            return true;
        }
        if ("false".equalsIgnoreCase(text) || "0".equals(text)) {
            return false;
        }
        return fallback;
    }
}
