package com.erp.inventory.service.impl;

import com.erp.inventory.config.WarningNotificationProperties;
import com.erp.inventory.entity.StockWarningRecord;
import com.erp.inventory.entity.StockWarningRule;
import com.erp.inventory.service.StockWarningNotificationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.stereotype.Service;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

/**
 * 库存预警通知服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class StockWarningNotificationServiceImpl implements StockWarningNotificationService {

    private final WarningNotificationProperties notificationProperties;

    @Override
    public boolean sendNotification(StockWarningRecord record, StockWarningRule rule) {
        if (rule == null || rule.getNotificationMethods() == null) {
            log.warn("预警规则或通知方式为空，跳过通知");
            return false;
        }

        boolean allSuccess = true;
        String[] methods = rule.getNotificationMethods().split(",");

        for (String method : methods) {
            method = method.trim();
            try {
                boolean success = switch (method) {
                    case "system" -> sendSystemNotification(record, rule);
                    case "email" -> sendEmailNotification(record, rule);
                    case "dingtalk" -> sendDingTalkNotification(record, rule);
                    default -> {
                        log.warn("未知的通知方式: {}", method);
                        yield false;
                    }
                };
                if (!success) {
                    allSuccess = false;
                }
            } catch (Exception e) {
                log.error("发送{}通知失败: {}", method, e.getMessage(), e);
                allSuccess = false;
            }
        }

        return allSuccess;
    }

    @Override
    public boolean sendSystemNotification(StockWarningRecord record, StockWarningRule rule) {
        if (!Boolean.TRUE.equals(notificationProperties.getSystemEnabled())) {
            log.info("系统通知未启用");
            return true;
        }

        // 系统通知只需要记录日志，实际的系统通知可以通过WebSocket等方式实现
        log.info("【系统通知】库存预警: {} - SKU: {}，仓库: {}，当前库存: {}，预警阈值: {}，消息: {}",
                record.getRuleName(),
                record.getSkuCode(),
                record.getWarehouseName(),
                record.getCurrentQuantity(),
                record.getWarningThreshold(),
                record.getMessage());

        return true;
    }

    @Override
    public boolean sendEmailNotification(StockWarningRecord record, StockWarningRule rule) {
        if (!Boolean.TRUE.equals(notificationProperties.getEmailEnabled())) {
            log.info("邮件通知未启用");
            return true;
        }

        if (rule.getNotificationEmails() == null || rule.getNotificationEmails().isEmpty()) {
            log.warn("未配置邮件通知地址");
            return false;
        }

        WarningNotificationProperties.EmailConfig emailConfig = notificationProperties.getEmail();
        if (emailConfig.getHost() == null || emailConfig.getFromEmail() == null) {
            log.warn("邮件配置不完整");
            return false;
        }

        try {
            JavaMailSender mailSender = createMailSender(emailConfig);

            String[] emails = rule.getNotificationEmails().split(",");
            for (String toEmail : emails) {
                toEmail = toEmail.trim();
                if (toEmail.isEmpty()) continue;

                SimpleMailMessage message = new SimpleMailMessage();
                message.setFrom(emailConfig.getFromName() + " <" + emailConfig.getFromEmail() + ">");
                message.setTo(toEmail);
                message.setSubject(buildEmailSubject(record));
                message.setText(buildEmailContent(record));

                mailSender.send(message);
                log.info("邮件通知发送成功: {}", toEmail);
            }

            return true;
        } catch (Exception e) {
            log.error("发送邮件通知失败: {}", e.getMessage(), e);
            return false;
        }
    }

    private JavaMailSender createMailSender(WarningNotificationProperties.EmailConfig config) {
        JavaMailSenderImpl sender = new JavaMailSenderImpl();
        sender.setHost(config.getHost());
        sender.setPort(config.getPort());
        sender.setUsername(config.getUsername());
        sender.setPassword(config.getPassword());

        Properties props = sender.getJavaMailProperties();
        props.put("mail.transport.protocol", "smtp");
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.starttls.enable", config.getUseTls());
        props.put("mail.smtp.connectiontimeout", "5000");
        props.put("mail.smtp.timeout", "5000");
        props.put("mail.smtp.writetimeout", "5000");

        return sender;
    }

    private String buildEmailSubject(StockWarningRecord record) {
        return String.format("【库存预警】%s - %s", record.getLevel(), record.getMessage());
    }

    private String buildEmailContent(StockWarningRecord record) {
        StringBuilder sb = new StringBuilder();
        sb.append("库存预警通知\n\n");
        sb.append("========================================\n\n");
        sb.append("预警规则: ").append(record.getRuleName()).append("\n");
        sb.append("预警类型: ").append(record.getRuleTypeLabel()).append("\n");
        sb.append("预警等级: ").append(record.getLevelLabel()).append("\n");
        sb.append("预警状态: ").append(record.getStatusLabel()).append("\n\n");
        sb.append("SKU编码: ").append(record.getSkuCode()).append("\n");
        sb.append("SKU名称: ").append(record.getSkuName()).append("\n");
        sb.append("仓库: ").append(record.getWarehouseName()).append("\n");
        sb.append("当前库存: ").append(record.getCurrentQuantity()).append("\n");
        sb.append("可用库存: ").append(record.getAvailableQuantity()).append("\n");
        sb.append("预警阈值: ").append(record.getWarningThreshold()).append("\n");
        sb.append("缺货量: ").append(record.getDeficit()).append("\n\n");
        sb.append("预警消息: ").append(record.getMessage()).append("\n\n");
        sb.append("预警时间: ").append(record.getCreatedAt()).append("\n");
        sb.append("========================================\n\n");
        sb.append("请及时处理！");
        return sb.toString();
    }

    @Override
    public boolean sendDingTalkNotification(StockWarningRecord record, StockWarningRule rule) {
        if (!Boolean.TRUE.equals(notificationProperties.getDingtalkEnabled())) {
            log.info("钉钉通知未启用");
            return true;
        }

        String webhookUrl = rule.getDingtalkWebhook();
        String secret = rule.getDingtalkSecret();

        if (webhookUrl == null || webhookUrl.isEmpty()) {
            log.warn("未配置钉钉Webhook URL");
            return false;
        }

        // 如果规则没有配置secret，使用全局配置的secret
        if (secret == null || secret.isEmpty()) {
            secret = notificationProperties.getDingtalk().getSecret();
        }

        try {
            String fullUrl = buildDingTalkUrl(webhookUrl, secret);
            String jsonBody = buildDingTalkMessage(record);

            // 发送HTTP请求
            java.net.HttpURLConnection conn = (java.net.HttpURLConnection)
                    new java.net.URL(fullUrl).openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setDoOutput(true);
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);

            try (var os = conn.getOutputStream()) {
                os.write(jsonBody.getBytes(StandardCharsets.UTF_8));
            }

            int responseCode = conn.getResponseCode();
            if (responseCode == 200) {
                log.info("钉钉通知发送成功");
                return true;
            } else {
                log.error("钉钉通知发送失败，响应码: {}", responseCode);
                return false;
            }
        } catch (Exception e) {
            log.error("发送钉钉通知失败: {}", e.getMessage(), e);
            return false;
        }
    }

    private String buildDingTalkUrl(String webhookUrl, String secret) {
        if (secret == null || secret.isEmpty()) {
            return webhookUrl;
        }

        try {
            long timestamp = System.currentTimeMillis();
            String stringToSign = timestamp + "\n" + secret;
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
            String sign = URLEncoder.encode(
                    Base64.getEncoder().encodeToString(mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8))),
                    StandardCharsets.UTF_8);

            String separator = webhookUrl.contains("?") ? "&" : "?";
            return webhookUrl + separator + "timestamp=" + timestamp + "&sign=" + sign;
        } catch (Exception e) {
            log.error("构建钉钉签名URL失败: {}", e.getMessage());
            return webhookUrl;
        }
    }

    private String buildDingTalkMessage(StockWarningRecord record) {
        // 使用钉钉Markdown格式
        String color = switch (record.getLevel()) {
            case "critical" -> "FF0000"; // 红色
            case "warning" -> "FFA500";    // 橙色
            default -> "00FF00";           // 绿色
        };

        return String.format("""
            {
                "msgtype": "markdown",
                "markdown": {
                    "title": "库存预警通知",
                    "text": "### 【%s】库存预警\\n\\n" +
                            "> **预警规则**: %s\\n\\n" +
                            "> **SKU**: %s (%s)\\n\\n" +
                            "> **仓库**: %s\\n\\n" +
                            "> **当前库存**: %d\\n\\n" +
                            "> **可用库存**: %d\\n\\n" +
                            "> **预警阈值**: %d\\n\\n" +
                            "> **缺货量**: %d\\n\\n" +
                            "> **预警消息**: %s\\n\\n" +
                            "> **预警时间**: %s"
                }
            }
            """,
                record.getLevelLabel(),
                record.getRuleName(),
                record.getSkuCode(), record.getSkuName(),
                record.getWarehouseName(),
                record.getCurrentQuantity(),
                record.getAvailableQuantity(),
                record.getWarningThreshold(),
                record.getDeficit(),
                record.getMessage(),
                record.getCreatedAt()
        );
    }

    @Override
    public boolean testDingTalkWebhook(String webhookUrl, String secret) {
        try {
            String fullUrl = buildDingTalkUrl(webhookUrl, secret);
            String jsonBody = """
                {
                    "msgtype": "text",
                    "text": {
                        "content": "库存预警系统测试消息"
                    }
                }
                """;

            java.net.HttpURLConnection conn = (java.net.HttpURLConnection)
                    new java.net.URL(fullUrl).openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setDoOutput(true);
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);

            try (var os = conn.getOutputStream()) {
                os.write(jsonBody.getBytes(StandardCharsets.UTF_8));
            }

            int responseCode = conn.getResponseCode();
            return responseCode == 200;
        } catch (Exception e) {
            log.error("测试钉钉Webhook失败: {}", e.getMessage());
            return false;
        }
    }

    @Override
    public boolean testEmail(String toEmail, String subject, String content) {
        if (!Boolean.TRUE.equals(notificationProperties.getEmailEnabled())) {
            log.info("邮件通知未启用");
            return false;
        }

        WarningNotificationProperties.EmailConfig emailConfig = notificationProperties.getEmail();
        if (emailConfig.getHost() == null || emailConfig.getFromEmail() == null) {
            log.warn("邮件配置不完整");
            return false;
        }

        try {
            JavaMailSender mailSender = createMailSender(emailConfig);

            SimpleMailMessage message = new SimpleMailMessage();
            message.setFrom(emailConfig.getFromName() + " <" + emailConfig.getFromEmail() + ">");
            message.setTo(toEmail);
            message.setSubject(subject);
            message.setText(content);

            mailSender.send(message);
            log.info("测试邮件发送成功: {}", toEmail);
            return true;
        } catch (Exception e) {
            log.error("发送测试邮件失败: {}", e.getMessage());
            return false;
        }
    }
}
