package com.qqchen.deploy.backend.notification.adapter.impl;

import com.qqchen.deploy.backend.framework.utils.JsonUtils;
import com.qqchen.deploy.backend.notification.adapter.INotificationChannelAdapter;
import com.qqchen.deploy.backend.notification.dto.WeworkSendNotificationRequest;
import com.qqchen.deploy.backend.notification.dto.wework.WeworkWebhookRequest;
import com.qqchen.deploy.backend.notification.entity.config.WeworkNotificationConfig;
import com.qqchen.deploy.backend.notification.enums.NotificationChannelTypeEnum;
import com.qqchen.deploy.backend.notification.enums.WeworkMessageTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

/**
 * 企业微信通知渠道适配器
 *
 * @author qqchen
 * @since 2025-11-03
 */
@Slf4j
@Component
public class WeworkChannelAdapter implements INotificationChannelAdapter<WeworkNotificationConfig, WeworkSendNotificationRequest> {
    
    private static final String BASE_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook";
    
    private final RestTemplate restTemplate = new RestTemplate();
    
    @Override
    public void send(WeworkNotificationConfig config, WeworkSendNotificationRequest request) throws Exception {
        // 1. 校验配置
        if (config.getKey() == null || config.getKey().isEmpty()) {
            throw new IllegalArgumentException("企业微信 Webhook Key 未配置");
        }
        
        // 2. 根据消息类型处理
        switch (request.getMessageType()) {
            case FILE -> sendFileMessage(config, request);
            case TEXT, MARKDOWN -> sendTextOrMarkdownMessage(config, request);
        }
    }
    
    /**
     * 发送文本或Markdown消息
     */
    private void sendTextOrMarkdownMessage(WeworkNotificationConfig config, WeworkSendNotificationRequest request) {
        String webhookUrl = BASE_URL + "/send?key=" + config.getKey();
        
        // 处理标题和内容的合并
        String finalContent = buildContentWithTitle(request);
        
        // 临时设置处理后的内容
        String originalContent = request.getContent();
        request.setContent(finalContent);
        
        // 转换为企微API格式
        var webhookRequest = request.toWebhookRequest();
        
        // 恢复原始内容
        request.setContent(originalContent);
        
        log.info("发送企业微信通知 - URL: {}, 类型: {}, 消息: {}", 
            webhookUrl, request.getMessageType().getApiType(), finalContent);
        
        // RestTemplate 自动序列化对象为JSON
        String response = restTemplate.postForObject(webhookUrl, webhookRequest, String.class);
        
        log.info("企业微信通知发送成功 - 响应: {}", response);
    }

    /**
     * 构建带标题的内容
     */
    private String buildContentWithTitle(WeworkSendNotificationRequest request) {
        String content = request.getContent();
        String title = request.getTitle();
        
        // 如果没有标题，直接返回内容
        if (title == null || title.trim().isEmpty()) {
            return content;
        }
        
        // 根据消息类型合并标题和内容
        return switch (request.getMessageType()) {
            case MARKDOWN -> title + "\n\n" + content;
            case TEXT -> title + "\n" + content;
            case FILE -> content; // 文件类型不处理标题
        };
    }
    
    /**
     * 发送文件消息
     */
    private void sendFileMessage(WeworkNotificationConfig config, WeworkSendNotificationRequest request) {
        if (request.getFilePath() == null || request.getFilePath().isEmpty()) {
            throw new IllegalArgumentException("文件路径不能为空");
        }
        
        // 1. 上传文件获取 media_id
        String uploadUrl = BASE_URL + "/upload_media?key=" + config.getKey() + "&type=file";
        String mediaId = uploadFile(uploadUrl, request.getFilePath());
        
        if (mediaId == null) {
            throw new RuntimeException("文件上传失败，未获取到 media_id");
        }
        
        // 2. 转换为企微API格式（带media_id）
        String sendUrl = BASE_URL + "/send?key=" + config.getKey();
        var webhookRequest = request.toWebhookRequest(mediaId);
        
        log.info("发送企业微信文件消息 - 文件: {}, mediaId: {}", request.getFileName(), mediaId);
        
        // RestTemplate 自动序列化对象为JSON
        String response = restTemplate.postForObject(sendUrl, webhookRequest, String.class);
        
        log.info("企业微信文件消息发送成功 - 响应: {}", response);
    }
    
    @Override
    public NotificationChannelTypeEnum supportedType() {
        return NotificationChannelTypeEnum.WEWORK;
    }
    
    @Override
    public void sendFile(WeworkNotificationConfig config, String filePath, String fileName) throws Exception {
        try {
            // 1. 校验配置
            if (config.getKey() == null || config.getKey().isEmpty()) {
                throw new IllegalArgumentException("企业微信 Webhook Key 未配置");
            }
            
            // 2. 上传文件获取 media_id
            String uploadUrl = BASE_URL + "/upload_media?key=" + config.getKey() + "&type=file";
            String mediaId = uploadFile(uploadUrl, filePath);
            
            if (mediaId == null) {
                throw new RuntimeException("文件上传失败，未获取到 media_id");
            }
            
            // 3. 构建文件消息请求
            WeworkSendNotificationRequest request = new WeworkSendNotificationRequest();
            request.setMessageType(WeworkMessageTypeEnum.FILE);
            var webhookRequest = request.toWebhookRequest(mediaId);
            
            // 4. 发送文件消息
            String sendUrl = BASE_URL + "/send?key=" + config.getKey();
            
            log.info("发送企业微信文件 - fileName: {}, mediaId: {}", fileName, mediaId);
            
            String response = restTemplate.postForObject(sendUrl, webhookRequest, String.class);
            
            log.info("企业微信文件发送成功 - 响应: {}", response);
            
        } catch (Exception e) {
            log.error("企业微信文件发送失败: filePath={}", filePath, e);
            throw e;
        }
    }
    
    @Override
    public String validateConfig(WeworkNotificationConfig config) {
        if (config.getKey() == null || config.getKey().isEmpty()) {
            return "Webhook Key 不能为空";
        }
        return "配置有效";
    }
    
    @Override
    public void testConnection(WeworkNotificationConfig config) throws Exception {
        // 1. 校验配置
        if (config.getKey() == null || config.getKey().isEmpty()) {
            throw new IllegalArgumentException("企业微信 Webhook Key 未配置");
        }
        
        // 2. 构建测试消息 URL
        String webhookUrl = BASE_URL + "/send?key=" + config.getKey();
        
        // 3. 构建测试消息
        WeworkWebhookRequest testRequest = WeworkWebhookRequest.builder()
            .msgtype("text")
            .text(WeworkWebhookRequest.TextContent.builder()
                .content("【测试消息】\n这是一条来自 Deploy Ease Platform 的测试消息，您的企业微信通知渠道配置正常！")
                .build())
            .build();
        
        log.info("测试企业微信连接 - URL: {}", webhookUrl);
        
        // 4. 发送测试请求（RestTemplate 自动序列化对象为JSON）
        String response = restTemplate.postForObject(webhookUrl, testRequest, String.class);
        
        log.info("企业微信连接测试成功 - 响应: {}", response);
        
        // 5. 检查响应
        if (response != null && response.contains("\"errcode\":0")) {
            log.info("企业微信通知渠道测试成功");
        } else {
            throw new Exception("企业微信响应异常: " + response);
        }
    }
    
    
    /**
     * 判断是否是 Markdown 格式消息
     * 企业微信支持的 Markdown 标签包括：
     * - <font color="xxx">文本</font>
     * - **加粗**
     * - `代码`
     * - [链接](url)
     * 
     * @param message 消息内容
     * @return true 如果包含 Markdown 标签
     */
    private boolean isMarkdownMessage(String message) {
        if (message == null || message.isEmpty()) {
            return false;
        }
        
        // 检测企业微信 Markdown 特征标签
        return message.contains("<font") || 
               message.contains("**") || 
               message.contains("`") || 
               message.matches(".*\\[.*\\]\\(.*\\).*"); // [text](url) 格式
    }
    
    /**
     * 上传文件到企业微信
     */
    private String uploadFile(String uploadUrl, String filePath) {
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                log.error("文件不存在: {}", filePath);
                return null;
            }
            
            // 构建 multipart 请求
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.MULTIPART_FORM_DATA);
            
            MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
            body.add("media", new FileSystemResource(file));
            
            HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
            
            // 发送请求
            ResponseEntity<String> response = restTemplate.postForEntity(uploadUrl, requestEntity, String.class);
            
            if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
                // 解析响应获取 media_id
                com.fasterxml.jackson.databind.JsonNode jsonNode = JsonUtils.parseJson(response.getBody());
                if (jsonNode == null) {
                    log.error("文件上传响应解析失败");
                    return null;
                }
                
                int errcode = jsonNode.get("errcode").asInt();
                if (errcode == 0) {
                    String mediaId = jsonNode.get("media_id").asText();
                    log.info("文件上传成功, media_id: {}", mediaId);
                    return mediaId;
                } else {
                    log.error("文件上传失败, errcode: {}, errmsg: {}", 
                        errcode, jsonNode.get("errmsg").asText());
                    return null;
                }
            }
            
            return null;
            
        } catch (Exception e) {
            log.error("上传文件到企业微信失败: filePath={}", filePath, e);
            return null;
        }
    }
    

}

