package com.gxwebsoft.common.system.controller;

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.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.UserOauthService;
import com.gxwebsoft.common.system.service.UserRoleService;
import com.gxwebsoft.common.system.service.UserService;
import com.gxwebsoft.common.system.vo.WxOfficialButton;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
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
@Api(tags = "微信公众号接口")
@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=";
  @Resource
  private UserService userService;
  @Resource
  private RoleService roleService;
  @Resource
  private UserRoleService userRoleService;
  @Resource
  private UserOauthService userOauthService;
  @Resource
  private RedisUtil redisUtil;

  @ApiOperation("验证微信服务器")
  @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 = "gxwebsoft";
    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;
  }

  @ApiOperation("接收微信的xml消息")
  @Transactional(rollbackFor = {Exception.class})
  @RequestMapping("/{id}")
  @ResponseBody
  public String receiveMessages(HttpServletRequest request,@PathVariable("id") Integer tenantId) throws IOException {
    System.out.println("tenantId = " + tenantId);
    Integer userId = 0; // 用户ID
    // 从请求中获取XML数据
    String xmlData = IOUtils.toString(request.getInputStream(), "UTF-8");
    System.out.println("xmlData = " + xmlData);
    // 解析XML数据
    Document document = XmlUtil.parseXml(xmlData);
    Element rootElement = XmlUtil.getRootElement(document);
    Element FromUserName = XmlUtil.getElement(rootElement, "FromUserName");
    String openId = FromUserName.getTextContent();
    System.out.println("openId = " + openId);
    if(StrUtil.isNotBlank(openId)){
      // 获取用户基本信息(UnionID机制)
      final String userStr = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + getAccessToken() + "&openid="+ openId +"&lang=zh_CN");
      // 保存第三方用户信息表shop_user_oauth
      final JSONObject jsonObject = JSONObject.parseObject(userStr);
      final String unionid = jsonObject.getString("unionid");
      final String subscribe = jsonObject.getString("subscribe");
      System.out.println("unionid = " + unionid);
      sendTemplateMessage(openId);
      // 关注操作
      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 = " + 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.setStatus(0);
            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("guest");
            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);
            }
            System.out.println("新微信公众号用户 = " + userId);
          }
          // 更新
          if (!CollectionUtils.isEmpty(list)) {
            for (UserOauth item: list){
              if(item.getUserId() != null){
                userId = item.getUserId();
              }
            }
            System.out.println("其他平台有注册过 = " + 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);
        }
      }

    }
    return null;
  }

  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());
  }

  @ApiOperation("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() {
    String key = MP_OFFICIAL.concat(":access_token:5");
    // 从缓存获取access_token
    String value = redisUtil.get(key);
    if (value != null) {
      // 解析access_token
      JSONObject response = JSON.parseObject(value);
      return response.getString("access_token");
    }
    // 微信获取凭证接口https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
    String apiUrl = "https://api.weixin.qq.com/cgi-bin/token";
    // 组装url参数
    String url = apiUrl.concat("?grant_type=client_credential").concat("&appid=").concat(appid).concat("&secret=").concat(secret);
    // 执行get请求
    String result = HttpUtil.get(url);
    // 解析access_token
    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;
  }

  @ApiOperation("创建公众号菜单接口")
  @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);
  }

  @ApiOperation("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());
  }
}
