package com.dora.service.impl;

import com.dora.dto.WechatManagementDto;
import com.dora.entity.WechatMenu;
import com.dora.entity.WechatMessageTemplate;
import com.dora.entity.WechatKeywordReply;
import com.dora.entity.WechatNewsArticle;
import com.dora.exception.WechatManagementException;
import com.dora.mapper.WechatMenuMapper;
import com.dora.mapper.WechatMessageTemplateMapper;
import com.dora.mapper.WechatKeywordReplyMapper;
import com.dora.mapper.WechatNewsArticleMapper;
import com.dora.service.WechatManagementService;
import com.dora.service.WeChatAccessTokenService;
import com.dora.service.WeChatMessageService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.menu.WxMenu;
import me.chanjar.weixin.common.bean.menu.WxMenuButton;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.material.WxMpMaterial;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialFileBatchGetResult;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 微信公众号管理服务实现
 * 
 * @author dora
 * @date 2024/12/01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WechatManagementServiceImpl implements WechatManagementService {

    private final WechatMenuMapper wechatMenuMapper;
    private final WechatMessageTemplateMapper wechatMessageTemplateMapper;
    private final WechatKeywordReplyMapper wechatKeywordReplyMapper;
    private final WechatNewsArticleMapper wechatNewsArticleMapper;
    private final WeChatAccessTokenService accessTokenService;
    private final WeChatMessageService messageService;
    private final WxMpService wxMpService;

    private static final String CREATE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=%s";
    private static final String GET_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=%s";
    private static final String DELETE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=%s";

    // ==================== 菜单管理实现 ====================

    @Override
    public List<WechatMenu> getMenuTree() {
        try {
            List<WechatMenu> allMenus = wechatMenuMapper.selectMenuTree();
            return buildMenuTree(allMenus);
        } catch (Exception e) {
            log.error("获取菜单树失败", e);
            return new ArrayList<>();
        }
    }

    @Override
    public WechatMenu getMenuById(Long id) {
        return wechatMenuMapper.selectById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WechatMenu createMenu(WechatManagementDto.MenuCreateRequest request) {
        try {
            // 验证菜单配置
            validateMenuRequest(request);

            WechatMenu menu = new WechatMenu();
            menu.setParentId(request.getParentId() != null ? request.getParentId() : 0L);
            menu.setMenuName(request.getMenuName());
            menu.setMenuType(request.getMenuType());
            menu.setMenuKey(request.getMenuKey());
            menu.setMenuUrl(request.getMenuUrl());
            menu.setMediaId(request.getMediaId());
            menu.setAppid(request.getAppid());
            menu.setPagepath(request.getPagepath());
            menu.setDescription(request.getDescription());
            menu.setIsEnabled(1);

            // 设置排序顺序
            if (request.getSortOrder() != null) {
                menu.setSortOrder(request.getSortOrder());
            } else {
                Integer maxSort = wechatMenuMapper.getMaxSortOrder(menu.getParentId());
                menu.setSortOrder(maxSort != null ? maxSort + 1 : 1);
            }

            wechatMenuMapper.insert(menu);
            log.info("创建菜单成功 - ID: {}, 名称: {}", menu.getId(), menu.getMenuName());
            return menu;

        } catch (Exception e) {
            log.error("创建菜单失败", e);
            throw new RuntimeException("创建菜单失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WechatMenu updateMenu(Long id, WechatManagementDto.MenuUpdateRequest request) {
        try {
            WechatMenu existingMenu = wechatMenuMapper.selectById(id);
            if (existingMenu == null) {
                throw new RuntimeException("菜单不存在");
            }

            // 更新菜单信息
            if (StringUtils.hasText(request.getMenuName())) {
                existingMenu.setMenuName(request.getMenuName());
            }
            if (StringUtils.hasText(request.getMenuType())) {
                existingMenu.setMenuType(request.getMenuType());
            }
            if (request.getMenuKey() != null) {
                existingMenu.setMenuKey(request.getMenuKey());
            }
            if (request.getMenuUrl() != null) {
                existingMenu.setMenuUrl(request.getMenuUrl());
            }
            if (request.getMediaId() != null) {
                existingMenu.setMediaId(request.getMediaId());
            }
            if (request.getAppid() != null) {
                existingMenu.setAppid(request.getAppid());
            }
            if (request.getPagepath() != null) {
                existingMenu.setPagepath(request.getPagepath());
            }
            if (request.getSortOrder() != null) {
                existingMenu.setSortOrder(request.getSortOrder());
            }
            if (request.getIsEnabled() != null) {
                existingMenu.setIsEnabled(request.getIsEnabled());
            }
            if (request.getDescription() != null) {
                existingMenu.setDescription(request.getDescription());
            }

            wechatMenuMapper.updateById(existingMenu);
            log.info("更新菜单成功 - ID: {}, 名称: {}", id, existingMenu.getMenuName());
            return existingMenu;

        } catch (Exception e) {
            log.error("更新菜单失败 - ID: {}", id, e);
            throw new RuntimeException("更新菜单失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteMenu(Long id) {
        try {
            WechatMenu menu = wechatMenuMapper.selectById(id);
            if (menu == null) {
                return false;
            }

            // 先删除所有子菜单
            wechatMenuMapper.deleteByParentId(id);
            
            // 再删除当前菜单
            int result = wechatMenuMapper.deleteById(id);
            
            log.info("删除菜单成功 - ID: {}, 名称: {}", id, menu.getMenuName());
            return result > 0;

        } catch (Exception e) {
            log.error("删除菜单失败 - ID: {}", id, e);
            return false;
        }
    }

    @Override
    public boolean updateMenuStatus(List<Long> ids, boolean enabled) {
        try {
            int result = wechatMenuMapper.updateStatusBatch(ids, enabled ? 1 : 0);
            log.info("批量更新菜单状态成功 - 数量: {}, 状态: {}", result, enabled);
            return result > 0;
        } catch (Exception e) {
            log.error("批量更新菜单状态失败", e);
            return false;
        }
    }

    @Override
    @Transactional
    public boolean publishMenu() {
        try {
            // 1. 从数据库获取启用的菜单项
            List<WechatMenu> allMenus = wechatMenuMapper.selectAllEnabled();
            if (CollectionUtils.isEmpty(allMenus)) {
                log.warn("发布菜单失败：数据库中没有启用的菜单项。");
                // 如果没有菜单，可以选择删除线上菜单
                wxMpService.getMenuService().menuDelete();
                log.info("已成功删除线上菜单。");
                return true;
            }

            // 2. 构建 WxMenu 对象
            WxMenu wxMenu = buildWxMenu(allMenus);

            // 3. 调用 wx-java SDK 发布菜单
            wxMpService.getMenuService().menuCreate(wxMenu);

            log.info("通过SDK发布微信菜单成功。");
            return true;

        } catch (WxErrorException e) {
            log.error("发布菜单到微信失败，错误码: {}, 错误信息: {}", e.getError().getErrorCode(), e.getError().getErrorMsg(), e);
            throw new WechatManagementException("发布菜单到微信失败: " + e.getError().getErrorMsg());
        } catch (Exception e) {
            log.error("发布菜单异常", e);
            throw new WechatManagementException("发布菜单时发生未知错误: " + e.getMessage());
        }
    }

    @Override
    public boolean deleteWechatMenu() {
        try {
            String accessToken = accessTokenService.getAccessToken();
            String url = String.format(DELETE_MENU_URL, accessToken);

            RestTemplate restTemplate = new RestTemplate();
            String response = restTemplate.getForObject(url, String.class);

            JSONObject result = JSON.parseObject(response);
            boolean success = result.getInteger("errcode") == 0;

            if (success) {
                log.info("删除微信菜单成功");
            } else {
                log.error("删除微信菜单失败 - errcode: {}, errmsg: {}", 
                         result.getInteger("errcode"), result.getString("errmsg"));
            }

            return success;

        } catch (Exception e) {
            log.error("删除微信菜单异常", e);
            return false;
        }
    }

    @Override
    public WechatManagementDto.WechatMenuResponse getCurrentWechatMenu() {
        try {
            String accessToken = accessTokenService.getAccessToken();
            String url = String.format(GET_MENU_URL, accessToken);

            RestTemplate restTemplate = new RestTemplate();
            String response = restTemplate.getForObject(url, String.class);

            JSONObject result = JSON.parseObject(response);
            
            WechatManagementDto.WechatMenuResponse menuResponse = new WechatManagementDto.WechatMenuResponse();
            
            if (result.getInteger("errcode") == 0 && result.containsKey("menu")) {
                menuResponse.setExists(true);
                menuResponse.setMenuConfig(result.getJSONObject("menu").toJSONString());
                menuResponse.setLastUpdateTime(LocalDateTime.now());
            } else {
                menuResponse.setExists(false);
            }

            return menuResponse;

        } catch (Exception e) {
            log.error("获取当前微信菜单异常", e);
            WechatManagementDto.WechatMenuResponse menuResponse = new WechatManagementDto.WechatMenuResponse();
            menuResponse.setExists(false);
            return menuResponse;
        }
    }

    // ==================== 消息模板管理实现 ====================

    @Override
    public WechatManagementDto.TemplatePageResponse getTemplateList(WechatManagementDto.TemplateQueryRequest request) {
        try {
            int offset = (request.getPage() - 1) * request.getSize();
            
            List<WechatMessageTemplate> templates = wechatMessageTemplateMapper.selectTemplateList(
                request.getTemplateName(),
                request.getTemplateType(),
                request.getTriggerType(),
                request.getIsEnabled(),
                offset,
                request.getSize()
            );

            int total = wechatMessageTemplateMapper.countTemplateList(
                request.getTemplateName(),
                request.getTemplateType(),
                request.getTriggerType(),
                request.getIsEnabled()
            );

            int totalPages = (int) Math.ceil((double) total / request.getSize());

            return new WechatManagementDto.TemplatePageResponse(
                templates, total, request.getPage(), request.getSize(), totalPages
            );

        } catch (Exception e) {
            log.error("获取模板列表失败", e);
            return new WechatManagementDto.TemplatePageResponse(
                new ArrayList<>(), 0, request.getPage(), request.getSize(), 0
            );
        }
    }

    @Override
    public WechatMessageTemplate getTemplateById(Long id) {
        return wechatMessageTemplateMapper.selectById(id);
    }

    @Override
    public WechatMessageTemplate getTemplateByKey(String templateKey) {
        return wechatMessageTemplateMapper.selectByTemplateKey(templateKey);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WechatMessageTemplate createTemplate(WechatManagementDto.TemplateCreateRequest request) {
        try {
            // 验证模板Key是否已存在
            if (wechatMessageTemplateMapper.existsByTemplateKey(request.getTemplateKey(), null)) {
                throw new RuntimeException("模板Key已存在: " + request.getTemplateKey());
            }

            WechatMessageTemplate template = new WechatMessageTemplate();
            template.setTemplateKey(request.getTemplateKey());
            template.setTemplateName(request.getTemplateName());
            template.setTemplateType(request.getTemplateType());
            template.setTriggerType(request.getTriggerType());
            template.setTriggerValue(request.getTriggerValue());
            template.setContent(request.getContent());
            template.setMediaId(request.getMediaId());
            template.setTitle(request.getTitle());
            template.setDescription(request.getDescription());
            template.setPicUrl(request.getPicUrl());
            template.setUrl(request.getUrl());
            template.setMusicUrl(request.getMusicUrl());
            template.setHqMusicUrl(request.getHqMusicUrl());
            template.setThumbMediaId(request.getThumbMediaId());
            template.setPriority(request.getPriority() != null ? request.getPriority() : 0);
            template.setIsEnabled(1);

            wechatMessageTemplateMapper.insert(template);
            
            // 验证模板ID是否生成
            if (template.getId() == null) {
                throw new WechatManagementException("模板ID生成失败，无法创建图文文章");
            }
            
            log.info("消息模板插入成功 - ID: {}, Key: {}", template.getId(), template.getTemplateKey());
            
            // 验证模板是否真的存在于数据库（防止外键约束问题）
            WechatMessageTemplate verifyTemplate = wechatMessageTemplateMapper.selectById(template.getId());
            if (verifyTemplate == null) {
                log.error("模板插入后验证失败 - ID: {}, 可能是事务同步问题", template.getId());
                throw new WechatManagementException("模板插入验证失败，无法继续创建图文文章");
            }
            log.debug("模板验证成功 - ID: {}, Key: {}", verifyTemplate.getId(), verifyTemplate.getTemplateKey());

            // 如果是图文消息，创建文章
            if ("news".equals(request.getTemplateType()) && request.getArticles() != null && !request.getArticles().isEmpty()) {
                log.debug("准备创建图文文章 - templateId: {}, 文章数量: {}", template.getId(), request.getArticles().size());
                createNewsArticles(template.getId(), request.getArticles());
            }

            log.info("创建消息模板成功 - ID: {}, Key: {}", template.getId(), template.getTemplateKey());
            return template;

        } catch (Exception e) {
            log.error("创建消息模板失败", e);
            throw new RuntimeException("创建消息模板失败: " + e.getMessage());
        }
    }

    // ==================== 辅助方法 ====================

    /**
     * 构建菜单树结构
     */
    private List<WechatMenu> buildMenuTree(List<WechatMenu> allMenus) {
        Map<Long, WechatMenu> menuMap = allMenus.stream()
                .collect(Collectors.toMap(WechatMenu::getId, menu -> menu));

        List<WechatMenu> rootMenus = new ArrayList<>();

        for (WechatMenu menu : allMenus) {
            if (menu.getParentId() == null || menu.getParentId() == 0) {
                menu.setLevel(1);
                menu.setChildren(new ArrayList<>());
                rootMenus.add(menu);
            } else {
                WechatMenu parent = menuMap.get(menu.getParentId());
                if (parent != null) {
                    menu.setLevel(2);
                    if (parent.getChildren() == null) {
                        parent.setChildren(new ArrayList<>());
                    }
                    parent.getChildren().add(menu);
                }
            }
        }

        // 排序
        rootMenus.sort(Comparator.comparing(WechatMenu::getSortOrder, 
                Comparator.nullsLast(Comparator.naturalOrder())));
        
        for (WechatMenu menu : rootMenus) {
            if (menu.getChildren() != null) {
                menu.getChildren().sort(Comparator.comparing(WechatMenu::getSortOrder, 
                        Comparator.nullsLast(Comparator.naturalOrder())));
                menu.setIsLeaf(menu.getChildren().isEmpty());
            } else {
                menu.setIsLeaf(true);
            }
        }

        return rootMenus;
    }

    /**
     * 构建微信菜单JSON
     */
    private Map<String, Object> buildWechatMenuJson(List<WechatMenu> menuTree) {
        Map<String, Object> menuData = new HashMap<>();
        List<Map<String, Object>> buttons = new ArrayList<>();

        for (WechatMenu menu : menuTree) {
            Map<String, Object> button = new HashMap<>();
            button.put("name", menu.getMenuName());

            if (menu.getChildren() != null && !menu.getChildren().isEmpty()) {
                // 有子菜单
                List<Map<String, Object>> subButtons = new ArrayList<>();
                for (WechatMenu child : menu.getChildren()) {
                    Map<String, Object> subButton = buildMenuButton(child);
                    subButtons.add(subButton);
                }
                button.put("sub_button", subButtons);
            } else {
                // 无子菜单，直接设置菜单属性
                Map<String, Object> menuButton = buildMenuButton(menu);
                button.putAll(menuButton);
            }

            buttons.add(button);
        }

        menuData.put("button", buttons);
        return menuData;
    }

    /**
     * 构建单个菜单按钮
     */
    private Map<String, Object> buildMenuButton(WechatMenu menu) {
        Map<String, Object> button = new HashMap<>();
        button.put("name", menu.getMenuName());
        button.put("type", menu.getMenuType());

        switch (menu.getMenuType()) {
            case "click":
                button.put("key", menu.getMenuKey());
                break;
            case "view":
                button.put("url", menu.getMenuUrl());
                break;
            case "miniprogram":
                button.put("url", menu.getMenuUrl());
                button.put("appid", menu.getAppid());
                button.put("pagepath", menu.getPagepath());
                break;
            default:
                if (StringUtils.hasText(menu.getMenuKey())) {
                    button.put("key", menu.getMenuKey());
                }
                if (StringUtils.hasText(menu.getMediaId())) {
                    button.put("media_id", menu.getMediaId());
                }
                break;
        }

        return button;
    }

    /**
     * 验证菜单请求
     */
    private void validateMenuRequest(WechatManagementDto.MenuCreateRequest request) {
        if (!StringUtils.hasText(request.getMenuName())) {
            throw new RuntimeException("菜单名称不能为空");
        }
        if (request.getMenuName().length() > 16) {
            throw new RuntimeException("菜单名称不能超过16个字符");
        }
        
        // 如果 parentId 为 0 或 null，说明是一级菜单
        // 一级菜单如果有子菜单，就不需要设置 type
        // 这里只能在创建时验证，如果后续会添加子菜单，需要清空type
        
        // 如果设置了 menuType，说明是叶子菜单，需要验证对应字段
        if (StringUtils.hasText(request.getMenuType())) {
            // 根据菜单类型验证必填字段
            switch (request.getMenuType()) {
                case "click":
                case "scancode_push":
                case "scancode_waitmsg":
                case "pic_sysphoto":
                case "pic_photo_or_album":
                case "pic_weixin":
                case "location_select":
                    if (!StringUtils.hasText(request.getMenuKey())) {
                        throw new RuntimeException(request.getMenuType() + "类型菜单必须设置menuKey");
                    }
                    // 确保没有设置url
                    if (StringUtils.hasText(request.getMenuUrl())) {
                        throw new RuntimeException(request.getMenuType() + "类型菜单不应该设置menuUrl，请使用menuKey");
                    }
                    break;
                    
                case "view":
                    if (!StringUtils.hasText(request.getMenuUrl())) {
                        throw new RuntimeException("view类型菜单必须设置menuUrl");
                    }
                    // 确保没有设置key
                    if (StringUtils.hasText(request.getMenuKey())) {
                        throw new RuntimeException("view类型菜单不应该设置menuKey，请使用menuUrl");
                    }
                    break;
                    
                case "miniprogram":
                    if (!StringUtils.hasText(request.getAppid()) || !StringUtils.hasText(request.getPagepath())) {
                        throw new RuntimeException("miniprogram类型菜单必须设置appid和pagepath");
                    }
                    break;
                    
                case "media_id":
                case "view_limited":
                    if (!StringUtils.hasText(request.getMediaId())) {
                        throw new RuntimeException(request.getMenuType() + "类型菜单必须设置mediaId");
                    }
                    break;
            }
        }
    }

    /**
     * 创建图文消息文章
     */
    private void createNewsArticles(Long templateId, List<WechatManagementDto.NewsArticleRequest> articleRequests) {
        if (articleRequests == null || articleRequests.isEmpty()) {
            log.warn("图文文章列表为空，跳过创建");
            return;
        }
        
        log.info("开始创建图文文章 - templateId: {}, 文章数量: {}", templateId, articleRequests.size());
        
        for (int i = 0; i < articleRequests.size(); i++) {
            try {
                WechatManagementDto.NewsArticleRequest request = articleRequests.get(i);
                
                // 验证必填字段
                if (request.getTitle() == null || request.getTitle().trim().isEmpty()) {
                    log.error("图文文章标题不能为空 - 索引: {}", i);
                    throw new WechatManagementException("第" + (i + 1) + "篇文章标题不能为空");
                }
                
                WechatNewsArticle article = new WechatNewsArticle();
                article.setTemplateId(templateId);
                article.setTitle(request.getTitle());
                article.setAuthor(request.getAuthor());
                article.setDigest(request.getDigest());
                article.setContent(request.getContent());
                article.setContentSourceUrl(request.getContentSourceUrl());
                article.setThumbMediaId(request.getThumbMediaId());
                // 为TINYINT字段设置默认值，避免null导致的插入失败
                article.setShowCoverPic(request.getShowCoverPic() != null ? request.getShowCoverPic() : 0);
                article.setUrl(request.getUrl());
                article.setThumbUrl(request.getThumbUrl());
                article.setNeedOpenComment(request.getNeedOpenComment() != null ? request.getNeedOpenComment() : 0);
                article.setOnlyFansCanComment(request.getOnlyFansCanComment() != null ? request.getOnlyFansCanComment() : 0);
                article.setSortOrder(request.getSortOrder() != null ? request.getSortOrder() : i);

                // 详细打印所有字段及其类型（用于调试）
                log.debug("【插入前检查】图文文章字段详情:");
                log.debug("  templateId: {} ({})", article.getTemplateId(), article.getTemplateId() != null ? article.getTemplateId().getClass().getSimpleName() : "null");
                log.debug("  title: {} ({})", article.getTitle(), article.getTitle() != null ? article.getTitle().getClass().getSimpleName() : "null");
                log.debug("  author: {} ({})", article.getAuthor(), article.getAuthor() != null ? article.getAuthor().getClass().getSimpleName() : "null");
                log.debug("  digest: {} ({})", article.getDigest(), article.getDigest() != null ? article.getDigest().getClass().getSimpleName() : "null");
                log.debug("  content: {} ({})", 
                          article.getContent() != null ? "[" + article.getContent().length() + " chars]" : "null",
                          article.getContent() != null ? article.getContent().getClass().getSimpleName() : "null");
                log.debug("  contentSourceUrl: {} ({})", article.getContentSourceUrl(), article.getContentSourceUrl() != null ? article.getContentSourceUrl().getClass().getSimpleName() : "null");
                log.debug("  thumbMediaId: {} ({})", article.getThumbMediaId(), article.getThumbMediaId() != null ? article.getThumbMediaId().getClass().getSimpleName() : "null");
                log.debug("  showCoverPic: {} ({})", article.getShowCoverPic(), article.getShowCoverPic() != null ? article.getShowCoverPic().getClass().getSimpleName() : "null");
                log.debug("  url: {} ({})", article.getUrl(), article.getUrl() != null ? article.getUrl().getClass().getSimpleName() : "null");
                log.debug("  thumbUrl: {} ({})", article.getThumbUrl(), article.getThumbUrl() != null ? article.getThumbUrl().getClass().getSimpleName() : "null");
                log.debug("  needOpenComment: {} ({})", article.getNeedOpenComment(), article.getNeedOpenComment() != null ? article.getNeedOpenComment().getClass().getSimpleName() : "null");
                log.debug("  onlyFansCanComment: {} ({})", article.getOnlyFansCanComment(), article.getOnlyFansCanComment() != null ? article.getOnlyFansCanComment().getClass().getSimpleName() : "null");
                log.debug("  sortOrder: {} ({})", article.getSortOrder(), article.getSortOrder() != null ? article.getSortOrder().getClass().getSimpleName() : "null");
                
                try {
                    wechatNewsArticleMapper.insert(article);
                    log.info("图文文章插入成功 - articleId: {}, title: {}", article.getId(), article.getTitle());
                } catch (Exception insertEx) {
                    // 尝试获取更深层的异常信息
                    Throwable cause = insertEx.getCause();
                    Throwable rootCause = insertEx;
                    while (rootCause.getCause() != null) {
                        rootCause = rootCause.getCause();
                    }
                    log.error("【MyBatis插入异常详情】");
                    log.error("  异常类型: {}", insertEx.getClass().getName());
                    log.error("  异常消息: {}", insertEx.getMessage());
                    log.error("  Cause类型: {}", cause != null ? cause.getClass().getName() : "null");
                    log.error("  Cause消息: {}", cause != null ? cause.getMessage() : "null");
                    log.error("  根异常类型: {}", rootCause.getClass().getName());
                    log.error("  根异常消息: {}", rootCause.getMessage());
                    throw insertEx;
                }
                
            } catch (Exception e) {
                log.error("插入图文文章失败 - 索引: {}, 错误: {}", i, e.getMessage(), e);
                throw new WechatManagementException("创建第" + (i + 1) + "篇图文文章失败: " + e.getMessage(), e);
            }
        }
        
        log.info("图文文章创建完成 - templateId: {}, 成功数量: {}", templateId, articleRequests.size());
    }

    /**
     * 将数据库中的菜单列表转换为 WxMenu 对象
     */
    private WxMenu buildWxMenu(List<WechatMenu> allMenus) {
        WxMenu wxMenu = new WxMenu();
        List<WxMenuButton> mainButtons = allMenus.stream()
                .filter(menu -> menu.getParentId() == null || menu.getParentId() == 0)
                .map(mainMenu -> {
                    // 验证并转换一级菜单
                    WxMenuButton mainButton = convertToWxMenuButton(mainMenu);
                    if (mainButton == null) {
                        log.warn("一级菜单验证失败，已跳过 - ID: {}, 名称: {}", mainMenu.getId(), mainMenu.getMenuName());
                        return null;
                    }
                    
                    // 验证并转换子菜单
                    List<WxMenuButton> subButtons = allMenus.stream()
                            .filter(subMenu -> mainMenu.getId().equals(subMenu.getParentId()))
                            .map(subMenu -> {
                                WxMenuButton subButton = convertToWxMenuButton(subMenu);
                                if (subButton == null) {
                                    log.warn("子菜单验证失败，已跳过 - ID: {}, 名称: {}", subMenu.getId(), subMenu.getMenuName());
                                }
                                return subButton;
                            })
                            .filter(btn -> btn != null) // 过滤掉无效的子菜单
                            .collect(Collectors.toList());
                    mainButton.setSubButtons(subButtons);
                    return mainButton;
                })
                .filter(btn -> btn != null) // 过滤掉无效的一级菜单
                .collect(Collectors.toList());
        wxMenu.setButtons(mainButtons);
        return wxMenu;
    }

    /**
     * 将 WechatMenu 实体转换为 WxMenuButton 对象
     * @return 返回转换后的按钮，如果数据无效则返回null
     */
    private WxMenuButton convertToWxMenuButton(WechatMenu menu) {
        WxMenuButton button = new WxMenuButton();
        button.setName(menu.getMenuName());
        
        // 只有叶子节点（非父菜单）才设置type和相关字段
        if (StringUtils.hasText(menu.getMenuType())) {
            button.setType(menu.getMenuType());
            
            // 根据菜单类型设置对应的字段，并验证必填字段
            switch (menu.getMenuType()) {
                case "view":
                    // view类型必须有url
                    if (!StringUtils.hasText(menu.getMenuUrl())) {
                        log.error("菜单数据无效：view类型菜单缺少URL - ID: {}, 名称: {}", menu.getId(), menu.getMenuName());
                        return null; // 返回null表示此菜单无效
                    }
                    button.setUrl(menu.getMenuUrl());
                    break;
                    
                case "click":
                case "scancode_push":
                case "scancode_waitmsg":
                case "pic_sysphoto":
                case "pic_photo_or_album":
                case "pic_weixin":
                case "location_select":
                    // 这些类型必须有key
                    if (!StringUtils.hasText(menu.getMenuKey())) {
                        log.error("菜单数据无效：{}类型菜单缺少Key - ID: {}, 名称: {}", menu.getMenuType(), menu.getId(), menu.getMenuName());
                        return null; // 返回null表示此菜单无效
                    }
                    button.setKey(menu.getMenuKey());
                    break;
                    
                case "miniprogram":
                    // 小程序类型需要设置url, appId, pagePath
                    if (!StringUtils.hasText(menu.getMenuUrl()) || !StringUtils.hasText(menu.getAppid()) || !StringUtils.hasText(menu.getPagepath())) {
                        log.error("菜单数据无效：miniprogram类型菜单缺少必要字段 - ID: {}, 名称: {}", menu.getId(), menu.getMenuName());
                        return null;
                    }
                    button.setUrl(menu.getMenuUrl());
                    button.setAppId(menu.getAppid());
                    button.setPagePath(menu.getPagepath());
                    break;
                    
                case "media_id":
                case "view_limited":
                    // 素材类型必须有media_id
                    if (!StringUtils.hasText(menu.getMediaId())) {
                        log.error("菜单数据无效：{}类型菜单缺少MediaId - ID: {}, 名称: {}", menu.getMenuType(), menu.getId(), menu.getMenuName());
                        return null;
                    }
                    button.setMediaId(menu.getMediaId());
                    break;
                    
                default:
                    // 默认情况，尝试设置key
                    if (StringUtils.hasText(menu.getMenuKey())) {
                        button.setKey(menu.getMenuKey());
                    } else {
                        log.warn("菜单类型未知或缺少必要字段 - ID: {}, 名称: {}, 类型: {}", menu.getId(), menu.getMenuName(), menu.getMenuType());
                    }
                    break;
            }
        }
        // 如果是父菜单（有子菜单），不设置type和key/url等字段
        
        return button;
    }

    // 其他方法的实现...
    // 由于篇幅限制，这里只展示核心方法的实现
    // 完整的实现会包括所有接口方法

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WechatMessageTemplate updateTemplate(Long id, WechatManagementDto.TemplateUpdateRequest request) {
        try {
            WechatMessageTemplate existingTemplate = wechatMessageTemplateMapper.selectById(id);
            if (existingTemplate == null) {
                throw new RuntimeException("消息模板不存在");
            }

            // 更新模板信息
            if (StringUtils.hasText(request.getTemplateName())) {
                existingTemplate.setTemplateName(request.getTemplateName());
            }
            if (StringUtils.hasText(request.getTemplateType())) {
                existingTemplate.setTemplateType(request.getTemplateType());
            }
            if (StringUtils.hasText(request.getTriggerType())) {
                existingTemplate.setTriggerType(request.getTriggerType());
            }
            if (request.getTriggerValue() != null) {
                existingTemplate.setTriggerValue(request.getTriggerValue());
            }
            if (request.getContent() != null) {
                existingTemplate.setContent(request.getContent());
            }
            if (request.getMediaId() != null) {
                existingTemplate.setMediaId(request.getMediaId());
            }
            if (request.getTitle() != null) {
                existingTemplate.setTitle(request.getTitle());
            }
            if (request.getDescription() != null) {
                existingTemplate.setDescription(request.getDescription());
            }
            if (request.getPicUrl() != null) {
                existingTemplate.setPicUrl(request.getPicUrl());
            }
            if (request.getUrl() != null) {
                existingTemplate.setUrl(request.getUrl());
            }
            if (request.getMusicUrl() != null) {
                existingTemplate.setMusicUrl(request.getMusicUrl());
            }
            if (request.getHqMusicUrl() != null) {
                existingTemplate.setHqMusicUrl(request.getHqMusicUrl());
            }
            if (request.getThumbMediaId() != null) {
                existingTemplate.setThumbMediaId(request.getThumbMediaId());
            }
            if (request.getIsEnabled() != null) {
                existingTemplate.setIsEnabled(request.getIsEnabled());
            }
            if (request.getPriority() != null) {
                existingTemplate.setPriority(request.getPriority());
            }

            wechatMessageTemplateMapper.updateById(existingTemplate);

            // 如果是图文消息，更新文章
            if ("news".equals(existingTemplate.getTemplateType()) && request.getArticles() != null) {
                // 先删除原有文章
                wechatNewsArticleMapper.deleteByTemplateId(id);
                // 创建新文章
                createNewsArticles(id, request.getArticles());
            }

            log.info("更新消息模板成功 - ID: {}, Key: {}", id, existingTemplate.getTemplateKey());
            return existingTemplate;

        } catch (Exception e) {
            log.error("更新消息模板失败 - ID: {}", id, e);
            throw new RuntimeException("更新消息模板失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteTemplate(Long id) {
        try {
            WechatMessageTemplate template = wechatMessageTemplateMapper.selectById(id);
            if (template == null) {
                return false;
            }

            // 先删除关联的图文消息文章
            wechatNewsArticleMapper.deleteByTemplateId(id);
            
            // 删除关联的关键词回复
            wechatKeywordReplyMapper.deleteByTemplateId(id);
            
            // 删除模板
            int result = wechatMessageTemplateMapper.deleteById(id);
            
            log.info("删除消息模板成功 - ID: {}, Key: {}", id, template.getTemplateKey());
            return result > 0;

        } catch (Exception e) {
            log.error("删除消息模板失败 - ID: {}", id, e);
            return false;
        }
    }

    @Override
    public boolean updateTemplateStatus(List<Long> ids, boolean enabled) {
        try {
            int result = wechatMessageTemplateMapper.updateStatusBatch(ids, enabled ? 1 : 0);
            log.info("批量更新模板状态成功 - 数量: {}, 状态: {}", result, enabled);
            return result > 0;
        } catch (Exception e) {
            log.error("批量更新模板状态失败", e);
            return false;
        }
    }

    @Override
    public WechatManagementDto.KeywordReplyPageResponse getKeywordReplyList(WechatManagementDto.KeywordReplyQueryRequest request) {
        try {
            int offset = (request.getPage() - 1) * request.getSize();
            
            List<WechatKeywordReply> keywordReplies = wechatKeywordReplyMapper.selectKeywordReplyList(
                request.getKeyword(),
                request.getMatchType(),
                request.getIsEnabled(),
                offset,
                request.getSize()
            );

            int total = wechatKeywordReplyMapper.countKeywordReplyList(
                request.getKeyword(),
                request.getMatchType(),
                request.getIsEnabled()
            );

            int totalPages = (int) Math.ceil((double) total / request.getSize());

            return new WechatManagementDto.KeywordReplyPageResponse(
                keywordReplies, total, request.getPage(), request.getSize(), totalPages
            );

        } catch (Exception e) {
            log.error("获取关键词回复列表失败", e);
            return new WechatManagementDto.KeywordReplyPageResponse(
                new ArrayList<>(), 0, request.getPage(), request.getSize(), 0
            );
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WechatKeywordReply createKeywordReply(WechatManagementDto.KeywordReplyCreateRequest request) {
        try {
            // 验证模板是否存在
            WechatMessageTemplate template = wechatMessageTemplateMapper.selectById(request.getTemplateId());
            if (template == null) {
                throw new RuntimeException("关联的消息模板不存在");
            }

            WechatKeywordReply keywordReply = new WechatKeywordReply();
            keywordReply.setKeyword(request.getKeyword());
            keywordReply.setMatchType(request.getMatchType() != null ? request.getMatchType() : "exact");
            keywordReply.setTemplateId(request.getTemplateId());
            keywordReply.setPriority(request.getPriority() != null ? request.getPriority() : 0);
            keywordReply.setIsEnabled(1);

            wechatKeywordReplyMapper.insert(keywordReply);
            
            log.info("创建关键词回复成功 - ID: {}, 关键词: {}", keywordReply.getId(), keywordReply.getKeyword());
            return keywordReply;

        } catch (Exception e) {
            log.error("创建关键词回复失败", e);
            throw new RuntimeException("创建关键词回复失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WechatKeywordReply updateKeywordReply(Long id, WechatManagementDto.KeywordReplyUpdateRequest request) {
        try {
            WechatKeywordReply existingKeywordReply = wechatKeywordReplyMapper.selectById(id);
            if (existingKeywordReply == null) {
                throw new RuntimeException("关键词回复不存在");
            }

            // 更新关键词回复信息
            if (StringUtils.hasText(request.getKeyword())) {
                existingKeywordReply.setKeyword(request.getKeyword());
            }
            if (StringUtils.hasText(request.getMatchType())) {
                existingKeywordReply.setMatchType(request.getMatchType());
            }
            if (request.getTemplateId() != null) {
                // 验证模板是否存在
                WechatMessageTemplate template = wechatMessageTemplateMapper.selectById(request.getTemplateId());
                if (template == null) {
                    throw new RuntimeException("关联的消息模板不存在");
                }
                existingKeywordReply.setTemplateId(request.getTemplateId());
            }
            if (request.getIsEnabled() != null) {
                existingKeywordReply.setIsEnabled(request.getIsEnabled());
            }
            if (request.getPriority() != null) {
                existingKeywordReply.setPriority(request.getPriority());
            }

            wechatKeywordReplyMapper.updateById(existingKeywordReply);
            
            log.info("更新关键词回复成功 - ID: {}, 关键词: {}", id, existingKeywordReply.getKeyword());
            return existingKeywordReply;

        } catch (Exception e) {
            log.error("更新关键词回复失败 - ID: {}", id, e);
            throw new RuntimeException("更新关键词回复失败: " + e.getMessage());
        }
    }

    @Override
    public boolean deleteKeywordReply(Long id) {
        try {
            WechatKeywordReply keywordReply = wechatKeywordReplyMapper.selectById(id);
            if (keywordReply == null) {
                return false;
            }

            int result = wechatKeywordReplyMapper.deleteById(id);
            
            log.info("删除关键词回复成功 - ID: {}, 关键词: {}", id, keywordReply.getKeyword());
            return result > 0;

        } catch (Exception e) {
            log.error("删除关键词回复失败 - ID: {}", id, e);
            return false;
        }
    }

    @Override
    public WechatMessageTemplate getTemplateByTrigger(String triggerType, String triggerValue) {
        try {
            List<WechatMessageTemplate> templates = wechatMessageTemplateMapper.selectByTrigger(triggerType, triggerValue);
            if (templates != null && !templates.isEmpty()) {
                // 返回优先级最高的模板
                return templates.stream()
                        .filter(WechatMessageTemplate::isEnabled)
                        .max(Comparator.comparing(WechatMessageTemplate::getPriorityValue))
                        .orElse(null);
            }
            return null;
        } catch (Exception e) {
            log.error("根据触发条件获取模板失败 - triggerType: {}, triggerValue: {}", triggerType, triggerValue, e);
            return null;
        }
    }

    @Override
    public WechatMessageTemplate getTemplateByKeyword(String keyword) {
        try {
            // 获取所有启用的关键词回复，按优先级排序
            List<WechatKeywordReply> keywordReplies = wechatKeywordReplyMapper.selectAllEnabled();
            
            for (WechatKeywordReply keywordReply : keywordReplies) {
                if (keywordReply.matches(keyword)) {
                    // 找到匹配的关键词，返回对应的模板
                    WechatMessageTemplate template = wechatMessageTemplateMapper.selectById(keywordReply.getTemplateId());
                    if (template != null && template.isEnabled()) {
                        return template;
                    }
                }
            }
            
            return null;
        } catch (Exception e) {
            log.error("根据关键词获取模板失败 - keyword: {}", keyword, e);
            return null;
        }
    }

    @Override
    public WechatMessageTemplate getDefaultReplyTemplate() {
        return wechatMessageTemplateMapper.selectDefaultReplyTemplate();
    }

    @Override
    public boolean sendTemplateMessage(String openid, WechatMessageTemplate template) {
        try {
            if (template == null || !template.isEnabled()) {
                return false;
            }
            
            switch (template.getTemplateType()) {
                case "text":
                    return messageService.sendTextMessage(openid, template.getContent());
                    
                case "news":
                    // 获取图文消息文章
                    List<WechatNewsArticle> articles = wechatNewsArticleMapper.selectByTemplateId(template.getId());
                    if (articles != null && !articles.isEmpty()) {
                        return messageService.sendNewsMessage(openid, articles);
                    }
                    return false;
                    
                case "image":
                    return messageService.sendImageMessage(openid, template.getMediaId());
                    
                case "voice":
                    return messageService.sendVoiceMessage(openid, template.getMediaId());
                    
                case "video":
                    return messageService.sendVideoMessage(openid, template.getMediaId(), 
                            template.getThumbMediaId(), template.getTitle(), template.getDescription());
                    
                case "music":
                    return messageService.sendMusicMessage(openid, template.getTitle(), 
                            template.getDescription(), template.getMusicUrl(), 
                            template.getHqMusicUrl(), template.getThumbMediaId());
                    
                default:
                    log.warn("不支持的消息模板类型: {} - templateId: {}", template.getTemplateType(), template.getId());
                    return false;
            }
            
        } catch (Exception e) {
            log.error("发送模板消息失败 - openid: {}, templateId: {}", openid, template.getId(), e);
            return false;
        }
    }

    @Override
    public WechatManagementDto.ManagementOverview getManagementOverview() {
        try {
            WechatManagementDto.ManagementOverview overview = new WechatManagementDto.ManagementOverview();
            
            // 菜单统计
            long menuCount = wechatMenuMapper.countMenus(null, 1); // 只统计启用的菜单
            overview.setMenuCount(menuCount);
            
            // 模板统计
            long templateCount = wechatMessageTemplateMapper.countTemplateList(null, null, null, 1); // 只统计启用的模板
            overview.setTemplateCount(templateCount);
            
            // 关键词回复统计
            long keywordReplyCount = wechatKeywordReplyMapper.countKeywordReplyList(null, null, 1); // 只统计启用的关键词回复
            overview.setKeywordReplyCount(keywordReplyCount);
            
            // 总配置数量
            overview.setTotalConfigCount(menuCount + templateCount + keywordReplyCount);
            
            return overview;
            
        } catch (Exception e) {
            log.error("获取管理概览失败", e);
            return new WechatManagementDto.ManagementOverview();
        }
    }

    // ==================== 素材管理实现 ====================

    @Override
    public WechatManagementDto.MediaUploadResult uploadPermanentMedia(MultipartFile file, String mediaType, String title, String introduction) throws IOException {
        if (file.isEmpty()) {
            throw new WechatManagementException("上传文件不能为空");
        }

        // 验证文件大小 - 根据微信公众号素材限制
        long fileSize = file.getSize();
        long maxSize = 0;
        switch (mediaType) {
            case "image":
            case "voice":
                maxSize = 2 * 1024 * 1024; // 2MB
                break;
            case "video":
                maxSize = 10 * 1024 * 1024; // 10MB
                break;
            case "thumb":
                maxSize = 64 * 1024; // 64KB
                break;
            default:
                throw new WechatManagementException("不支持的素材类型: " + mediaType + "，支持的类型：image, voice, video, thumb");
        }
        
        if (fileSize > maxSize) {
            String maxSizeStr = maxSize >= 1024 * 1024 ? (maxSize / (1024 * 1024)) + "MB" : (maxSize / 1024) + "KB";
            throw new WechatManagementException(String.format("文件大小超过限制！%s类型的素材最大为%s，当前文件大小：%.2fMB", 
                    mediaType, maxSizeStr, fileSize / (1024.0 * 1024.0)));
        }

        // 验证视频类型必须提供标题和描述
        if ("video".equals(mediaType) && (!StringUtils.hasText(title) || !StringUtils.hasText(introduction))) {
            throw new WechatManagementException("上传视频素材时，标题和描述不能为空");
        }

        File tempFile = null;
        try {
            // 1. 将 MultipartFile 转换为临时文件，保留原始文件扩展名
            String originalFilename = file.getOriginalFilename();
            String fileExtension = "";
            if (originalFilename != null && originalFilename.contains(".")) {
                fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
            }
            // 创建临时文件时使用原始扩展名，让微信能识别文件类型
            Path tempPath = Files.createTempFile("wechat_media_", fileExtension);
            file.transferTo(tempPath.toFile());
            tempFile = tempPath.toFile();
            
            // 2. 构建上传物料
            WxMpMaterial material = new WxMpMaterial();
            material.setFile(tempFile);
            material.setName(file.getOriginalFilename());
            if ("video".equals(mediaType)) {
                material.setVideoTitle(title);
                material.setVideoIntroduction(introduction);
            }

            // 3. 调用SDK上传
            WxMpMaterialUploadResult result = wxMpService.getMaterialService().materialFileUpload(mediaType, material);

            // 4. 封装返回结果
            WechatManagementDto.MediaUploadResult uploadResult = new WechatManagementDto.MediaUploadResult();
            uploadResult.setMediaId(result.getMediaId());
            uploadResult.setUrl(result.getUrl());

            log.info("上传永久素材成功 - mediaId: {}, url: {}", result.getMediaId(), result.getUrl());
            return uploadResult;

        } catch (WxErrorException e) {
            log.error("上传永久素材到微信失败", e);
            throw new WechatManagementException("上传素材失败: " + e.getError().getErrorMsg());
        } finally {
            // 5. 清理临时文件
            if (tempFile != null && tempFile.exists()) {
                if (!tempFile.delete()) {
                    log.warn("临时文件删除失败: {}", tempFile.getAbsolutePath());
                }
            }
        }
    }

    @Override
    public WechatManagementDto.MediaFilePageResponse listPermanentMedia(String mediaType, int page, int size) {
        try {
            // page从1开始，而微信API的offset从0开始
            int offset = (page - 1) * size;
            WxMpMaterialFileBatchGetResult result = wxMpService.getMaterialService().materialFileBatchGet(mediaType, offset, size);
            
            WechatManagementDto.MediaFilePageResponse response = new WechatManagementDto.MediaFilePageResponse();
            response.setTotal(result.getTotalCount());

            List<WechatManagementDto.MediaFileItem> items = new ArrayList<>();
            if (result.getItems() != null) {
                items = result.getItems().stream()
                        .map(item -> {
                            WechatManagementDto.MediaFileItem fileItem = new WechatManagementDto.MediaFileItem();
                            fileItem.setMediaId(item.getMediaId());
                            fileItem.setName(item.getName());
                            // 微信SDK返回的时间戳，需要类型转换并安全处理
                            try {
                                Object updateTime = item.getUpdateTime();
                                if (updateTime != null) {
                                    // 尝试转换为Long类型
                                    if (updateTime instanceof Long) {
                                        fileItem.setUpdateTime((Long) updateTime);
                                    } else if (updateTime instanceof Integer) {
                                        fileItem.setUpdateTime(((Integer) updateTime).longValue());
                                    } else if (updateTime instanceof Number) {
                                        fileItem.setUpdateTime(((Number) updateTime).longValue());
                                    } else {
                                        // 尝试字符串转换
                                        fileItem.setUpdateTime(Long.parseLong(updateTime.toString()));
                                    }
                                }
                            } catch (Exception e) {
                                log.warn("获取素材更新时间失败，mediaId: {}, error: {}", item.getMediaId(), e.getMessage());
                            }
                            fileItem.setUrl(item.getUrl());
                            return fileItem;
                        })
                        .collect(Collectors.toList());
            }
            response.setItems(items);

            return response;

        } catch (WxErrorException e) {
            log.error("获取永久素材列表失败", e);
            throw new WechatManagementException("获取素材列表失败: " + e.getError().getErrorMsg());
        }
    }

    @Override
    public boolean deletePermanentMedia(String mediaId) {
        try {
            boolean success = wxMpService.getMaterialService().materialDelete(mediaId);
            if (success) {
                log.info("删除永久素材成功 - mediaId: {}", mediaId);
            } else {
                log.warn("删除永久素材失败，微信端返回false - mediaId: {}", mediaId);
            }
            return success;
        } catch (WxErrorException e) {
            log.error("删除永久素材失败", e);
            throw new WechatManagementException("删除素材失败: " + e.getError().getErrorMsg());
        }
    }
}
