package com.gxwebsoft.common.system.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.internal.util.file.IOUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.qq.weixin.mp.aes.WXBizJsonMsgCrypt;
import com.gxwebsoft.auto.dto.QrLoginData;
import com.gxwebsoft.common.core.config.ConfigProperties;
import com.gxwebsoft.common.core.security.JwtSubject;
import com.gxwebsoft.common.core.security.JwtUtil;
import com.gxwebsoft.common.core.utils.CommonUtil;
import com.gxwebsoft.common.core.utils.JSONUtil;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.system.entity.*;
import com.gxwebsoft.common.system.param.RoleParam;
import com.gxwebsoft.common.system.param.UserParam;
import com.gxwebsoft.common.system.service.RoleService;
import com.gxwebsoft.common.system.service.SettingService;
import com.gxwebsoft.common.system.service.UserOauthService;
import com.gxwebsoft.common.system.service.UserRoleService;
import com.gxwebsoft.common.system.service.UserService;
import com.gxwebsoft.common.system.service.UserSyncService;
import com.gxwebsoft.common.system.service.WxService;
import com.gxwebsoft.common.system.vo.WxOfficialButton;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.gxwebsoft.common.core.constants.PlatformConstants.MP_OFFICIAL;

@Slf4j
@Tag(name = "微信公众号接口")
@RestController
@RequestMapping("/api/wx-official")
public class WxOfficialController extends BaseController {
  // 公众号AppID
  private static final String appid = "wxa67c676fc445590e";
  // 秘钥
  private static final String secret = "a450297b5ca8e081080148799d4e6b25";
  // 订阅消息模板ID
  private static final String templateId = "LBoByn-TLb2qJS7yR838lGRU-BA-RZE6jm-adb7AWPA";
  // 小程序APPID
  private static final String miniAppid = "wx541db955e7a62709";
  // 创建公众号菜单
  private static final String MENU_CREATE_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=";
  // 生成二维码接口
  private static final String QRCODE_CREATE_URL = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=";
  // 查看二维码接口
  private static final String QRCODE_SHOW_URL = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=";

  // 微信服务器配置（从配置文件读取或使用默认值）
  private static final String TOKEN = "gxwebsoft";
  private static final String ENCODING_AES_KEY = "ARve4au5GF2fE2cT13xpaHhuqS2yjE34gpVe8IZwd4C";

  @Resource
  private UserService userService;
  @Resource
  private RoleService roleService;
  @Resource
  private UserRoleService userRoleService;
  @Resource
  private UserSyncService userSyncService;
  @Resource
  private UserOauthService userOauthService;
  @Resource
  private SettingService settingService;
  @Resource
  private WxService wxService;
  @Resource
  private RedisUtil redisUtil;
  @Resource
  private ConfigProperties configProperties;

  @Operation(summary = "验证微信服务器")
  @GetMapping("/{id}")
  public String validate(@PathVariable("id") Integer tenantId, @RequestParam String nonce, @RequestParam String timestamp, @RequestParam String signature, @RequestParam String echostr) {
    System.out.println("nonce = " + nonce);
    System.out.println("tenantId = " + tenantId);
    if (tenantId == null) {
      return null;
    }
    String token = getOfficialToken();
    String[] array = new String[]{token, timestamp, nonce};
    // 将token、timestamp、nonce三个参数进行字典序排序
    Arrays.sort(array);
    // 将三个参数字符串拼接成一个字符串进行sha1加密
    StringBuilder sb = new StringBuilder();
    for (String str : array) {
      sb.append(str);
    }
    final String strSha1 = DigestUtil.sha1Hex(sb.toString());
    if (strSha1.equals(signature)) {
      return echostr;
    }
    return null;
  }

  @Operation(summary = "接收微信的消息推送")
  @Transactional(rollbackFor = {Exception.class})
  @PostMapping("/{id}")
  @ResponseBody
  public String receiveMessages(HttpServletRequest request, @PathVariable("id") Integer tenantId,
                                @RequestParam(required = false) String msg_signature,
                                @RequestParam(required = false) String timestamp,
                                @RequestParam(required = false) String nonce) throws Exception {
    System.out.println("========== 接收微信消息 ==========");
    System.out.println("tenantId = " + tenantId);
    System.out.println("msg_signature = " + msg_signature);

    // 从请求中获取XML数据
    String xmlData = IOUtils.toString(request.getInputStream(), "UTF-8");
    System.out.println("原始xmlData = " + xmlData);

    // 如果有加密参数，进行解密
    if (StrUtil.isNotBlank(msg_signature) && StrUtil.isNotBlank(xmlData) && xmlData.contains("Encrypt")) {
      try {
        Document encryptedDocument = XmlUtil.parseXml(xmlData);
        Element encryptedRoot = XmlUtil.getRootElement(encryptedDocument);
        Element encryptElement = XmlUtil.getElement(encryptedRoot, "Encrypt");
        String encryptedMessage = encryptElement != null ? encryptElement.getTextContent() : "";
        if (StrUtil.isBlank(encryptedMessage)) {
          log.error("消息解密失败: 未从XML报文中提取到Encrypt节点");
          return "error";
        }

        WXBizJsonMsgCrypt crypt = new WXBizJsonMsgCrypt(getOfficialToken(), getOfficialEncodingAESKey(), getOfficialAppId(tenantId));
        xmlData = crypt.DecryptXmlMsg(msg_signature, timestamp, nonce, encryptedMessage);
        System.out.println("解密后xmlData = " + xmlData);
      } catch (Exception e) {
        log.error("消息解密失败: {}", e.getMessage());
        return "error";
      }
    }

    // 解析XML数据
    Document document = XmlUtil.parseXml(xmlData);
    Element rootElement = XmlUtil.getRootElement(document);

    // 获取消息类型
    Element msgTypeElement = XmlUtil.getElement(rootElement, "MsgType");
    String msgType = msgTypeElement != null ? msgTypeElement.getTextContent() : "";
    System.out.println("msgType = " + msgType);

    // 获取事件类型（如果是事件消息）
    Element eventElement = XmlUtil.getElement(rootElement, "Event");
    String event = eventElement != null ? eventElement.getTextContent() : "";
    System.out.println("event = " + event);

    // 获取事件KEY（用于判断是否是扫码事件）
    Element eventKeyElement = XmlUtil.getElement(rootElement, "EventKey");
    String eventKey = eventKeyElement != null ? eventKeyElement.getTextContent() : "";
    System.out.println("eventKey = " + eventKey);

    // 获取用户openid
    Element FromUserName = XmlUtil.getElement(rootElement, "FromUserName");
    String openId = FromUserName != null ? FromUserName.getTextContent() : "";
    System.out.println("openId = " + openId);

    // 获取 ticket（扫码事件专用）
    Element ticketElement = XmlUtil.getElement(rootElement, "Ticket");
    String ticket = ticketElement != null ? ticketElement.getTextContent() : "";
    System.out.println("ticket = " + ticket);

    // 处理扫码关注事件
    if ("event".equals(msgType) && ("subscribe".equals(event) || "SCAN".equals(event))) {
      System.out.println("========== 处理扫码关注事件 ==========");

      // 获取扫码的 token（从 EventKey 中提取，格式：qrscene_xxx 或直接是 xxx）
      String token = "";
      if (StrUtil.isNotBlank(eventKey)) {
        if (eventKey.startsWith("qrscene_")) {
          token = eventKey.substring(8); // 去掉 qrscene_ 前缀
        } else {
          token = eventKey;
        }
      }
      System.out.println("扫码登录token = " + token);

      // 获取用户信息
      if (StrUtil.isNotBlank(openId)) {
        // 获取用户基本信息(UnionID机制)
        final String userStr = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + getAccessToken(tenantId) + "&openid=" + openId + "&lang=zh_CN");
        final JSONObject jsonObject = JSONObject.parseObject(userStr);
        final String unionid = jsonObject.getString("unionid");
        final String subscribe = jsonObject.getString("subscribe");
        System.out.println("unionid = " + unionid);
        System.out.println("subscribe = " + subscribe);

        Integer userId = processWxUser(tenantId, openId, unionid, subscribe);

        // 如果有关联的扫码登录token，完成登录
        if (StrUtil.isNotBlank(token) && userId != null && userId > 0) {
          completeQrLogin(token, userId, tenantId);
        }
      }
    }

    // 返回 success 表示处理成功
    return "success";
  }

  /**
   * 处理微信用户（关注/注册/登录）
   */
  private Integer processWxUser(Integer tenantId, String openId, String unionid, String subscribe) {
    Integer userId = 0;

    // 关注操作
    if (subscribe != null && subscribe.equals("1")) {
      final int count = userOauthService.count(new LambdaQueryWrapper<UserOauth>()
          .eq(UserOauth::getOauthType, MP_OFFICIAL)
          .eq(UserOauth::getUnionid, unionid)
          .eq(UserOauth::getTenantId, tenantId));
      System.out.println("已绑定用户数量 = " + count);

      if (count == 0) {
        // 检查其他平台是否有注册过
        final List<UserOauth> list = userOauthService.list(
            new LambdaQueryWrapper<UserOauth>()
                .eq(UserOauth::getUnionid, unionid)
                .eq(UserOauth::getDeleted, 0));
        final int size = list.size();

        // 新用户注册
        if (size == 0) {
          User user = new User();
          user.setStatus(0);
          user.setUsername("wxoff_".concat(RandomUtil.randomString(12)));
          user.setNickname("微信公众号用户");
          user.setPlatform(MP_OFFICIAL);
          user.setGradeId(1);
          user.setPassword(userService.encodePassword(CommonUtil.randomUUID16()));
          user.setTenantId(tenantId);
          user.setRecommend(0);
          final RoleParam roleParam = new RoleParam();
          roleParam.setTenantId(tenantId);
          roleParam.setRoleCode("user");
          Role role = roleService.getByRoleCode(roleParam);
          user.setRoleId(role.getRoleId());
          if (userService.saveUser(user)) {
            userId = user.getUserId();
            // 添加用户角色
            final UserRole userRole = new UserRole();
            userRole.setUserId(user.getUserId());
            userRole.setTenantId(user.getTenantId());
            userRole.setRoleId(user.getRoleId());
            userRoleService.save(userRole);
            // 注意：不立即同步到 websopy，等绑定手机号后再同步
          }
          System.out.println("新微信公众号用户 userId = " + userId);
        }

        // 更新
        if (!CollectionUtils.isEmpty(list)) {
          for (UserOauth item : list) {
            if (item.getUserId() != null) {
              userId = item.getUserId();
            }
          }
          System.out.println("其他平台有注册过 userId = " + userId);
        }

        // 保存第三方用户记录
        final UserOauth userOauth = new UserOauth();
        userOauth.setOauthType(MP_OFFICIAL);
        userOauth.setUnionid(unionid);
        userOauth.setOauthId(openId);
        userOauth.setUserId(userId);
        userOauth.setTenantId(tenantId);
        boolean save = userOauthService.save(userOauth);
        System.out.println("关注微信公众号保存结果 = " + save);
      } else {
        // 已绑定用户，获取userId
        UserOauth existingUser = userOauthService.getOne(new LambdaQueryWrapper<UserOauth>()
            .eq(UserOauth::getOauthType, MP_OFFICIAL)
            .eq(UserOauth::getUnionid, unionid)
            .eq(UserOauth::getTenantId, tenantId));
        if (existingUser != null) {
          userId = existingUser.getUserId();
          System.out.println("已存在绑定用户 userId = " + userId);
          // 即使已存在记录，也确保oauth记录存在（防止数据不一致）
          boolean oauthExists = userOauthService.count(new LambdaQueryWrapper<UserOauth>()
              .eq(UserOauth::getOauthType, MP_OFFICIAL)
              .eq(UserOauth::getUnionid, unionid)
              .eq(UserOauth::getTenantId, tenantId)
              .eq(UserOauth::getOauthId, openId)) > 0;
          if (!oauthExists) {
            // 创建oauth记录
            final UserOauth userOauth = new UserOauth();
            userOauth.setOauthType(MP_OFFICIAL);
            userOauth.setUnionid(unionid);
            userOauth.setOauthId(openId);
            userOauth.setUserId(userId);
            userOauth.setTenantId(tenantId);
            boolean save = userOauthService.save(userOauth);
            System.out.println("补充创建oauth记录，结果 = " + save);
          }
        } else {
          System.out.println("警告：count=1但未找到对应的绑定记录，unionid=" + unionid + ", tenantId=" + tenantId);
          // 这种情况可能是数据不一致，尝试创建新的oauth记录
          userId = findOrCreateUserForOauth(tenantId, openId, unionid);
        }
      }
    }

    return userId;
  }

  /**
   * 完成扫码登录
   */
  private void completeQrLogin(String token, Integer userId, Integer tenantId) {
    try {
      System.out.println("开始完成扫码登录: token=" + token + ", userId=" + userId + ", tenantId=" + tenantId);
      String redisKey = "qr-login:token:" + token;
      QrLoginData qrLoginData = redisUtil.get(redisKey, QrLoginData.class);
      if (qrLoginData == null) {
        qrLoginData = new QrLoginData();
        qrLoginData.setToken(token);
        qrLoginData.setCreateTime(DateUtil.formatDateTime(DateUtil.date()));
      }

      User user = userService.getAllByUserId(String.valueOf(userId));
      if (user == null) {
        log.warn("扫码登录完成时未找到用户，token={}, userId={}", token, userId);
        return;
      }

      // 1. 检查并确保用户有合适的角色
      ensureUserHasAppropriateRole(user, tenantId);

      long ttlSeconds = 120L;
      qrLoginData.setToken(token);
      qrLoginData.setUserId(userId);
      qrLoginData.setUsername(user.getUsername());
      qrLoginData.setTenantId(user.getTenantId() != null ? user.getTenantId() : tenantId);
      qrLoginData.setExpireTime(DateUtil.formatDateTime(DateUtil.offsetSecond(DateUtil.date(), (int) ttlSeconds)));

      if (StrUtil.isBlank(user.getPhone())) {
        qrLoginData.setStatus("bind_phone");
        qrLoginData.setNeedBindPhone(true);
        qrLoginData.setAccessToken(null);
        qrLoginData.setMessage("请先绑定手机号完成登录");
      } else {
        qrLoginData.setStatus("confirmed");
        qrLoginData.setNeedBindPhone(false);
        qrLoginData.setAccessToken(buildAccessToken(user));
        qrLoginData.setMessage("登录成功");
      }

      redisUtil.set(redisKey, qrLoginData, ttlSeconds, TimeUnit.SECONDS);
      log.info("扫码登录状态已更新，token={}, userId={}, status={}, needBindPhone={}, message={}, ttlSeconds={}",
          token, userId, qrLoginData.getStatus(), qrLoginData.getNeedBindPhone(),
          qrLoginData.getMessage(), ttlSeconds);
      System.out.println("扫码登录完成，token=" + token + ", userId=" + userId +
          ", status=" + qrLoginData.getStatus() + ", message=" + qrLoginData.getMessage());
    } catch (Exception e) {
      log.error("完成扫码登录失败", e);
      System.out.println("完成扫码登录异常: " + e.getMessage());
    }
  }

  private String buildAccessToken(User user) {
    JwtSubject jwtSubject = new JwtSubject(user.getUsername(), user.getTenantId());
    return JwtUtil.buildToken(jwtSubject, configProperties.getTokenExpireTime(), configProperties.getTokenKey());
  }

  @Operation(summary = "生成微信扫码登录二维码")
  @GetMapping("/qrcode/{token}")
  public ApiResult<?> generateQrCode(@PathVariable("token") String token) {
    try {
      // 生成带参数的二维码，scene 为 token
      String url = QRCODE_CREATE_URL + getAccessToken();

      // 创建临时二维码（有效期7天），scene_str 最大32个可见字符
      JSONObject params = new JSONObject();
      params.put("action_info", new JSONObject().put("scene", new JSONObject().put("scene_str", token)));
      params.put("action_name", "QR_STR_SCENE");
      params.put("expire_seconds", 604800); // 7天有效期

      String result = HttpRequest.post(url)
          .body(params.toJSONString())
          .timeout(10000)
          .execute().body();

      System.out.println("生成二维码结果: " + result);

      JSONObject jsonResult = JSONObject.parseObject(result);
      if (jsonResult.containsKey("ticket")) {
        String ticket = jsonResult.getString("ticket");
        String qrCodeUrl = QRCODE_SHOW_URL + java.net.URLEncoder.encode(ticket, "UTF-8");

        return success(qrCodeUrl);
      } else {
        return fail("生成二维码失败: " + result);
      }
    } catch (Exception e) {
      log.error("生成二维码异常: {}", e.getMessage());
      return fail("生成二维码异常: " + e.getMessage());
    }
  }

  private void sendTemplateMessage(String openId) {
    String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + getAccessToken();
    TemplateMessage templateMessage = new TemplateMessage();
    templateMessage.setToUser(openId);
    templateMessage.setTemplateId("dVSbX2NRzAG7IuN4kkCQhgV-LjzxvApN3PgrGlon9JU");

    /*
      您好，您已成功消费。

      商品名：微信影城影票
      消费时间：2013年8月20日 20:38
      备注：您可以回复文字或语音对该商品及商家进行评价哦~
      {{productType.DATA}}：{{name.DATA}} 消费时间：{{time.DATA}} {{remark.DATA}}
     */
    HashMap<String, TemplateMessageDTO> data = new HashMap<>();
    data.put("first", new TemplateMessageDTO("您收到了一条新的订单。"));
    data.put("tradeDateTime", new TemplateMessageDTO("02月18日 01时05分"));
    data.put("customerInfo", new TemplateMessageDTO("广州 王俊"));
    data.put("orderItemName", new TemplateMessageDTO("兴趣车型"));
    data.put("orderItemData", new TemplateMessageDTO("骐达 2011款 1.6 CVT 舒适版"));
    data.put("remark", new TemplateMessageDTO("截止24日09:39分,您尚有10个订单未处理。"));
    System.out.println("data = " + data);
    // 链式构建请求
    String result = HttpRequest.post(url)
      .body(JSONObject.toJSONString(data))//表单内容
      .timeout(20000)//超时，毫秒
      .execute().body();
    System.out.println("result = " + result);
    System.out.println("getAccessToken() = " + getAccessToken());
  }

  @Operation(summary = "send发送订阅通知")
  @PostMapping("/send")
  public ApiResult<?> send(UserParam param) {
    // send发送订阅通知
    String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/bizsend?access_token=" + getAccessToken();
    final UserOauth userOauth = userOauthService.getOne(new LambdaQueryWrapper<UserOauth>().eq(UserOauth::getUserId, param.getUserId()).eq(UserOauth::getOauthType, "MP-OFFICIAL").eq(UserOauth::getDeleted, 0));
    if (userOauth != null) {
      param.setOpenid(userOauth.getOauthId());
      final String oauthId = userOauth.getOauthId();
      // 跳转小程序链接
      HashMap<String, String> miniprogram = new HashMap<>();
      miniprogram.put("appid", miniAppid);
      miniprogram.put("pagepath", "pages/chat/chat?friendId=" + param.getUserId());
      // 参数
      HashMap<String, Object> data = new HashMap<>();
      final HashMap<String, String> thing1 = new HashMap<>();
      final HashMap<String, String> thing2 = new HashMap<>();
      thing1.put("value", "有新访客需要接待");
      thing2.put("value", "吉媒小红娘");
      data.put("thing1", thing1);
      data.put("thing2", thing2);

      // 请求主服务器获取用户信息
      HashMap<String, Object> map = new HashMap<>();
      map.put("access_token", getAccessToken());
      map.put("touser", oauthId); // "opEVj6e1YIlMyovkOQFCLJ7llmuI"
      // 红娘来信通知
      map.put("template_id", templateId);
      map.put("miniprogram", JSONObject.toJSONString(miniprogram));
      map.put("data", data);
      // 新访客通知
//    map.put("tid","XMpEsDHmZZqpiaAzmPqO0Gk_h39WCRkaNZ9VoSI9F34");
//    map.put("page","https://admin.jimeigroup.cn");
//    map.put("sceneDesc","消息提醒");
      System.out.println("map = " + map);

      // 链式构建请求
      String result = HttpRequest.post(url)
        .body(JSONObject.toJSONString(map))//表单内容
        .timeout(20000)//超时，毫秒
        .execute().body();

      JSONObject jsonObject = JSONObject.parseObject(result);
      System.out.println("jsonObject = " + jsonObject);
      if (jsonObject != null) {
        return success(jsonObject);
      }
    }

    return fail("请求失败", getAccessToken());
  }

  // 调用接口凭证
  private String getAccessToken() {
    return getAccessToken(null);
  }

  private String getAccessToken(Integer tenantId) {
    try {
      return wxService.getOfficialAccessToken(tenantId);
    } catch (Exception ex) {
      log.warn("从系统设置获取公众号access_token失败，回退到兼容逻辑: {}", ex.getMessage());
    }

    String key = MP_OFFICIAL.concat(":access_token:5");
    String value = redisUtil.get(key);
    if (value != null) {
      JSONObject response = JSON.parseObject(value);
      return response.getString("access_token");
    }

    String apiUrl = "https://api.weixin.qq.com/cgi-bin/token";
    String url = apiUrl.concat("?grant_type=client_credential").concat("&appid=").concat(appid).concat("&secret=").concat(secret);
    String result = HttpUtil.get(url);
    JSONObject response = JSON.parseObject(result);
    if (response.getString("access_token") != null) {
      redisUtil.set(key, result, 7000L, TimeUnit.SECONDS);
      return response.getString("access_token");
    }
    return null;
  }

  private String getOfficialToken() {
    try {
      JSONObject config = settingService.getBySettingKey("wx-official");
      String token = config.getString("token");
      return StrUtil.isNotBlank(token) ? token : TOKEN;
    } catch (Exception ex) {
      log.warn("读取公众号token配置失败，回退到硬编码值: {}", ex.getMessage());
      return TOKEN;
    }
  }

  private String getOfficialEncodingAESKey() {
    try {
      JSONObject config = settingService.getBySettingKey("wx-official");
      String encodingAESKey = config.getString("encodingAESKey");
      return StrUtil.isNotBlank(encodingAESKey) ? encodingAESKey : ENCODING_AES_KEY;
    } catch (Exception ex) {
      log.warn("读取公众号EncodingAESKey配置失败，回退到硬编码值: {}", ex.getMessage());
      return ENCODING_AES_KEY;
    }
  }

  private String getOfficialAppId(Integer tenantId) {
    try {
      return wxService.getOfficialAppId(tenantId);
    } catch (Exception ex) {
      log.warn("读取公众号AppId配置失败，回退到硬编码值: {}", ex.getMessage());
      return appid;
    }
  }

  @Operation(summary = "创建公众号菜单接口")
  @PostMapping("/createMenu")
  public ApiResult<?> createMenu() {
    String url = MENU_CREATE_URL.concat(Objects.requireNonNull(getAccessToken()));
    CloseableHttpClient httpClient = HttpClients.createDefault();
    HttpPost httpPost = new HttpPost(url);
    System.out.println("url = " + url);
    // 创建菜单数据
    ArrayList<WxOfficialButton> menu = new ArrayList<>();
    final WxOfficialButton button = new WxOfficialButton();
    button.setName("菜单1");
    button.setType("click");
    button.setKey("CLICK_EVENT");
    menu.add(button);
    button.setName("菜单2");
    button.setType("click");
    button.setKey("CLICK_EVENT");
    menu.add(button);
    button.setName("菜单3");
    button.setType("click");
    button.setKey("CLICK_EVENT");
    menu.add(button);

    System.out.println("menu = " + menu);
    httpPost.setEntity(new StringEntity(JSONUtil.toJSONString(menu), "UTF-8"));
    httpPost.setHeader("Content-type", "application/json");

    try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
      HttpEntity entity = response.getEntity();
      if (entity != null) {
        String result = EntityUtils.toString(entity, "UTF-8");
        System.out.println("result = " + result);
        if (!result.contains("ok")) {
          System.out.println("result = " + result);
          String key = MP_OFFICIAL.concat(":access_token:5");
          redisUtil.delete(key);
          return fail(result);
        }
        return success("返回结果", entity);
      }
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
    return fail("创建失败", url);
  }

  @Operation(summary = "test")
  @PostMapping("/test")
  public ApiResult<?> count() {
    final int count = userOauthService.count(new LambdaQueryWrapper<UserOauth>().eq(UserOauth::getOauthType, MP_OFFICIAL).eq(UserOauth::getUnionid, "o0FaIuKa2UsVp6FCbvmZlrcaBRCM"));
    System.out.println("count = " + count);
    return success(getAccessToken());
  }

  /**
   * 查找或创建用户用于oauth绑定
   */
  private Integer findOrCreateUserForOauth(Integer tenantId, String openId, String unionid) {
    Integer userId = 0;
    // 首先尝试通过unionid查找任何平台的现有用户
    final List<UserOauth> list = userOauthService.list(
        new LambdaQueryWrapper<UserOauth>()
            .eq(UserOauth::getUnionid, unionid)
            .eq(UserOauth::getDeleted, 0));

    if (!CollectionUtils.isEmpty(list)) {
      for (UserOauth item : list) {
        if (item.getUserId() != null) {
          userId = item.getUserId();
          break;
        }
      }
      System.out.println("数据不一致：通过unionid找到其他平台的用户 userId = " + userId);
    }

    // 如果没找到用户，创建一个新用户
    if (userId == 0) {
      User user = new User();
      user.setStatus(0);
      user.setUsername("wxoff_".concat(RandomUtil.randomString(12)));
      user.setNickname("微信公众号用户");
      user.setPlatform(MP_OFFICIAL);
      user.setGradeId(1);
      user.setPassword(userService.encodePassword(CommonUtil.randomUUID16()));
      user.setTenantId(tenantId);
      user.setRecommend(0);

      // 尝试获取"user"角色，不行就用"guest"，再不行用默认6
      Role role = null;
      try {
        final RoleParam roleParam = new RoleParam();
        roleParam.setTenantId(tenantId);
        roleParam.setRoleCode("user");
        role = roleService.getByRoleCode(roleParam);
      } catch (Exception e) {
        System.out.println("获取user角色失败，尝试guest角色");
        try {
          final RoleParam roleParam = new RoleParam();
          roleParam.setTenantId(tenantId);
          roleParam.setRoleCode("guest");
          role = roleService.getByRoleCode(roleParam);
        } catch (Exception ex) {
          System.out.println("获取guest角色也失败，使用默认角色ID 6");
        }
      }

      user.setRoleId(role != null ? role.getRoleId() : 6);

      if (userService.saveUser(user)) {
        userId = user.getUserId();
        // 添加用户角色
        final UserRole userRole = new UserRole();
        userRole.setUserId(user.getUserId());
        userRole.setTenantId(user.getTenantId());
        userRole.setRoleId(user.getRoleId());
        userRoleService.save(userRole);
        // 注意：不立即同步到 websopy，等绑定手机号后再同步
      }
      System.out.println("数据不一致：创建新用户 userId = " + userId);
    }

    // 创建oauth记录
    final UserOauth userOauth = new UserOauth();
    userOauth.setOauthType(MP_OFFICIAL);
    userOauth.setUnionid(unionid);
    userOauth.setOauthId(openId);
    userOauth.setUserId(userId);
    userOauth.setTenantId(tenantId);
    boolean save = userOauthService.save(userOauth);
    System.out.println("创建oauth记录修复数据不一致，结果 = " + save);

    return userId;
  }

  /**
   * 确保用户有合适的角色
   */
  private void ensureUserHasAppropriateRole(User user, Integer tenantId) {
    try {
      // 检查用户是否有有效的角色绑定
      List<UserRole> userRoles = userRoleService.list(new LambdaQueryWrapper<UserRole>()
          .eq(UserRole::getUserId, user.getUserId())
          .eq(UserRole::getTenantId, tenantId));

      if (CollectionUtils.isEmpty(userRoles)) {
        System.out.println("用户 " + user.getUserId() + " 没有角色绑定，尝试分配角色");

        // 获取合适的角色
        Role role = null;
        // 先尝试获取"user"角色
        try {
          final RoleParam roleParam = new RoleParam();
          roleParam.setTenantId(tenantId);
          roleParam.setRoleCode("user");
          role = roleService.getByRoleCode(roleParam);
        } catch (Exception e) {
          System.out.println("获取user角色失败，尝试guest角色");
          try {
            final RoleParam roleParam = new RoleParam();
            roleParam.setTenantId(tenantId);
            roleParam.setRoleCode("guest");
            role = roleService.getByRoleCode(roleParam);
          } catch (Exception ex) {
            System.out.println("获取guest角色也失败，使用默认角色ID 6");
          }
        }

        Integer roleId = role != null ? role.getRoleId() : 6;

        // 创建用户角色绑定
        final UserRole userRole = new UserRole();
        userRole.setUserId(user.getUserId());
        userRole.setTenantId(tenantId);
        userRole.setRoleId(roleId);
        userRoleService.save(userRole);

        // 更新用户的roleId
        user.setRoleId(roleId);
        userService.updateUser(user);

        System.out.println("为用户 " + user.getUserId() + " 分配了角色ID: " + roleId);
      } else {
        // 检查角色的有效性
        boolean hasValidRole = false;
        for (UserRole userRole : userRoles) {
          if (userRole.getRoleId() != null && userRole.getRoleId() > 0) {
            hasValidRole = true;
            // 确保用户的roleId与绑定的角色一致
            if (!userRole.getRoleId().equals(user.getRoleId())) {
              user.setRoleId(userRole.getRoleId());
              userService.updateUser(user);
              System.out.println("更新用户 " + user.getUserId() + " 的角色ID为: " + userRole.getRoleId());
            }
            break;
          }
        }

        if (!hasValidRole) {
          System.out.println("用户 " + user.getUserId() + " 的角色绑定无效，重新分配");
          // 重新分配角色（简化逻辑，使用默认角色ID 6）
          final UserRole userRole = new UserRole();
          userRole.setUserId(user.getUserId());
          userRole.setTenantId(tenantId);
          userRole.setRoleId(6);
          userRoleService.save(userRole);

          user.setRoleId(6);
          userService.updateUser(user);

          System.out.println("重新为用户 " + user.getUserId() + " 分配了默认角色ID: 6");
        }
      }
    } catch (Exception e) {
      System.out.println("确保用户角色时发生异常: " + e.getMessage());
      e.printStackTrace();
    }
  }

}
