package com.fs.app.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.core.date.DateTime;
import com.fs.app.annotation.Login;
import com.fs.app.annotation.UserOperationLog;
import com.fs.app.enums.ErrorCode;
import com.fs.app.param.FsUserLoginByMpParam;
import com.fs.app.utils.JwtUtils;
import com.fs.common.core.domain.R;
import com.fs.common.core.redis.RedisCache;
import com.fs.core.config.WxMaConfiguration;
import com.fs.course.mapper.FsCourseSopLogsMapper;
import com.fs.course.mapper.FsCourseWatchLogMapper;
import com.fs.his.domain.FsUser;
import com.fs.his.enums.FsUserOperationEnum;
import com.fs.his.service.IFsUserService;
import com.fs.his.utils.ConfigUtil;
import com.fs.his.utils.PhoneUtil;
import com.fs.qw.mapper.QwExternalContactMapper;
import com.fs.sop.params.QwSopSettingTimeParam;
import com.fs.system.mapper.SysConfigMapper;
import com.fs.wx.mp.WxEeventType;
import com.fs.wx.mp.WxMessageType;
import com.fs.wx.mp.WxServiceMsgDto;
import io.swagger.annotations.ApiOperation;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.bean.menu.WxMenu;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpMenuService;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.WxMpUserService;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;


@Slf4j
@RestController
@RequestMapping("/app/wx/mp")
public class WxMpController extends AppBaseController {
  Logger logger= LoggerFactory.getLogger(getClass());
  @Autowired
  private WxMpService wxMpService;
  private static final String MP_TOKEN = "U2qmxEbsp0PJFoLRvUDvIjVi9XPzuVc2";

  private static final String EncodingAESKey = "P3HE7Gd1PJVQqCLoOMop5uYfjx9LwfY53rnC3VUuLZS";

  @Autowired
  private IFsUserService userService;

  @Autowired
  JwtUtils jwtUtils;
  @Autowired
  RedisCache redisCache;

  @Autowired
  private ConfigUtil configUtil;

  @Autowired
  private SysConfigMapper sysConfigMapper;

  @Autowired
  FsCourseWatchLogMapper fsCourseWatchLogMapper;
  @Autowired
  QwExternalContactMapper qwExternalContactMapper;
  @Autowired
  private FsCourseSopLogsMapper courseSopLogsMapper;


  //公众号事件回调
  @PostMapping
  public String checkWxToken(@RequestParam(value = "signature", required = false) String signature,
                             @RequestParam(value = "timestamp", required = false) String timestamp,
                             @RequestParam(name = "nonce", required = false) String nonce,
                             @RequestParam(value = "echostr", required = false) String echostr,
                             @RequestBody(required = false) WxServiceMsgDto wxServiceMsgDto) throws WxErrorException{
    // 只处理订阅与取消订阅消息
    if (null != wxServiceMsgDto && StringUtils.isNotEmpty(wxServiceMsgDto.getMsgType()) &&
            StringUtils.isNotEmpty(wxServiceMsgDto.getEvent())) {
      String msgType = wxServiceMsgDto.getMsgType();
      String event = wxServiceMsgDto.getEvent();
      // 判断是否是订阅或取消订阅事件
      boolean isSubscribeEvent = WxMessageType.EVENT.getCode().equals(msgType) &&
              (WxEeventType.SUBSCRIBE.getCode().equals(event) || WxEeventType.UNSUBSCRIBE.getCode().equals(event));
      if (isSubscribeEvent) {
        WxEeventType wxEeventType = WxEeventType.SUBSCRIBE.getCode().equals(event) ? WxEeventType.SUBSCRIBE : WxEeventType.UNSUBSCRIBE;
        logger.info("公众号关注回调:{}",wxEeventType);
        logger.info("公众号关注回调详情:{}",wxServiceMsgDto);
        WxMpUserService wxMpUserService = wxMpService.getUserService();
        WxMpUser wxMpUser = wxMpUserService.userInfo(wxServiceMsgDto.getFromUserName());
        logger.info("获取用户信息:{}",wxMpUser);
        if (wxMpUser != null && wxMpUser.getUnionId()!=null) {
          FsUser user = userService.selectFsUserByUnionid(wxMpUser.getUnionId());
          if (user != null) {
            // 根据事件类型更新 isOfficialAccountAuth 字段
            if (WxEeventType.SUBSCRIBE.equals(wxEeventType)) {
              user.setIsOfficialAccountAuth(1); // 设置为已关注
            } else if (WxEeventType.UNSUBSCRIBE.equals(wxEeventType)) {
              user.setIsOfficialAccountAuth(0); // 设置为取消关注
            }
            userService.updateFsUser(user); // 保存更新后的用户信息
          }else {
            //写入
            user=new FsUser();
//            user.setPhone(code);
            user.setNickName("匿名用户**");
            user.setAvatar("https://hos-1309931967.cos.ap-chongqing.myqcloud.com/fs/20230725/a848605591384ec29d49773dd58d9345.jpg");
            user.setStatus(1);
            user.setMpOpenId(wxMpUser.getOpenId());
            user.setUnionId(wxMpUser.getUnionId());
            user.setIsOfficialAccountAuth(wxMpUser.getSubscribe()? 1 : 0);
            user.setCreateTime(new Date());
            userService.insertFsUser(user);
          }
        }
      }
    }
    return "success";
  }

  @GetMapping
  public String checkWxToken(
          @RequestParam("signature") String signature,
          @RequestParam("timestamp") String timestamp,
          @RequestParam("nonce") String nonce,
          @RequestParam("echostr") String echostr) {
    logger.info("数据回调URLServer-微信调用dataGet请求");
    boolean check = wxMpService.checkSignature(timestamp,nonce,signature);
    logger.info("验证结果：{}",check);
    if (check){
      return echostr;
    }
    return "error";
  }

  @PostMapping("/createMenu")
  public R createMenu(@RequestBody WxMenu wxMenu) throws WxErrorException{
    WxMpMenuService wxMpMenuService = wxMpService.getMenuService();
    try{
      wxMpMenuService.menuCreate(wxMenu);
      return R.ok("创建成功");
    }catch (WxErrorException e){
      logger.error(e.getMessage());
      return R.error("创建失败");
    }
  }

  @Login
  @ApiOperation("绑定手机号")
  @PostMapping("/setIPhoneNumber")
  public R setIPhoneNumber(@RequestBody FsUserLoginByMpParam param) {
    log.info("=====================进入小程序授权登录, 入参: {}", param);

    // 参数校验
    if (StringUtils.isBlank(param.getCode())) {
      log.warn("绑定手机号失败：code参数为空");
      return R.error(ErrorCode.PARAM_EMPTY.getCode(), "授权码不能为空");
    }

    if (StringUtils.isBlank(param.getAppId())) {
      log.warn("绑定手机号失败：appId参数为空");
      return R.error(ErrorCode.PARAM_EMPTY.getCode(), "应用ID不能为空");
    }

    WxMaService wxService = null;
    try {
      // 获取微信服务实例
      wxService = WxMaConfiguration.getMaService(param.getAppId());
      if (wxService == null) {
        log.error("绑定手机号失败：未找到对应的微信小程序服务，appId={}", param.getAppId());
        return R.error(ErrorCode.WX_SERVICE_NOT_FOUND.getCode(), "微信服务初始化失败");
      }

      // 获取session信息
      WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(param.getCode());
      if (session == null || StringUtils.isEmpty(session.getOpenid())) {
        log.warn("绑定手机号失败：获取session信息异常，code={}", param.getCode());
        return R.error(ErrorCode.WX_SESSION_FAILED.getCode(), "微信授权失败，请重新尝试");
      }

      // 解密手机号信息
      WxMaPhoneNumberInfo phoneNoInfo = null;
      try {
        phoneNoInfo = wxService.getUserService().getPhoneNoInfo(
                session.getSessionKey(),
                param.getEncryptedData(),
                param.getIv()
        );
      } catch (Exception e) {
        log.error("解密手机号失败：sessionKey={}, encryptedData={}, iv={}",
                session.getSessionKey(), param.getEncryptedData(), param.getIv(), e);
        return R.error(ErrorCode.WX_DECRYPT_FAILED.getCode(), "手机号解密失败");
      }

      if (phoneNoInfo == null || StringUtils.isEmpty(phoneNoInfo.getPhoneNumber())) {
        log.warn("绑定手机号失败：获取的手机号为空");
        return R.error(ErrorCode.WX_PHONE_EMPTY.getCode(), "未获取到手机号信息");
      }

      // 获取当前用户并更新手机号
      String currentUserId = getUserId();
      if (StringUtils.isBlank(currentUserId)) {
        log.error("绑定手机号失败：用户ID获取失败");
        return R.error(ErrorCode.USER_NOT_LOGIN.getCode(), "用户未登录");
      }

      Long userId;
      try {
        userId = Long.valueOf(currentUserId);
      } catch (NumberFormatException e) {
        log.error("绑定手机号失败：用户ID格式错误，userIdStr={}", currentUserId, e);
        return R.error(ErrorCode.PARAM_FORMAT_ERROR.getCode(), "用户ID格式错误");
      }

      FsUser user = userService.selectFsUserByUserId(userId);
      if (user == null) {
        log.error("绑定手机号失败：用户不存在，userId={}", userId);
        return R.error(ErrorCode.USER_NOT_EXIST.getCode(), "用户不存在");
      }

      // 检查手机号是否已被绑定
      String phoneNumber = phoneNoInfo.getPhoneNumber();
      if (StringUtils.isNotBlank(user.getPhone())) {
        log.warn("绑定手机号失败：该用户已绑定手机号，userId={}, existingPhone={}", userId, user.getPhone());
        return R.ok().put("code",ErrorCode.PHONE_ALREADY_BOUND.getCode()).put("msg", "该账号已绑定手机号").put("user",user);
      }

      // 检查手机号是否已被其他用户绑定
      FsUser existingUser = userService.selectFsUserByPhone(phoneNumber);
      if (existingUser == null) {
        existingUser = userService.selectFsUserByPhone(PhoneUtil.encryptPhone(phoneNumber));
      }
      if (existingUser != null && !existingUser.getUserId().equals(userId)) {
        log.warn("绑定手机号失败：手机号已被其他用户绑定，phone={}, existingUserId={}",
                phoneNumber, existingUser.getUserId());
        return R.error(ErrorCode.PHONE_ALREADY_USED.getCode(), "该手机号已被其他账号绑定");
      }

      // 更新用户手机号
      user.setPhone(phoneNumber);
      int updateResult = userService.updateFsUser(user);

      if (updateResult <= 0) {
        log.error("绑定手机号失败：数据库更新失败，userId={}, phone={}", userId, phoneNumber);
        return R.error(ErrorCode.DB_UPDATE_FAILED.getCode(), "手机号绑定失败");
      }

      log.info("绑定手机号成功：userId={}, phone={}", userId, phoneNumber);
      return R.ok("手机号绑定成功").put("user", user);

    } catch (WxErrorException e) {
      log.error("微信服务调用异常：code={}, appId={}, error={}",
              param.getCode(), param.getAppId(), e.getMessage(), e);

      // 根据微信错误码返回具体提示
      int wxErrorCode = e.getError().getErrorCode();
      String errorMsg = getWxErrorMsg(wxErrorCode);
      return R.error(ErrorCode.WX_API_ERROR.getCode(), errorMsg);

    } catch (Exception e) {
      log.error("绑定手机号系统异常：param={}", param, e);
      return R.error(ErrorCode.SYSTEM_ERROR.getCode(), "系统繁忙，请稍后再试");
    }
  }

  /**
   * 根据微信错误码获取友好提示信息
   */
  private String getWxErrorMsg(int wxErrorCode) {
    switch (wxErrorCode) {
      case 40029: return "授权码无效或已过期";
      case 45011: return "操作频率限制，请稍后再试";
      case 40013: return "无效的AppID";
      case 40125: return "无效的AppSecret";
      case 41008: return "缺少code参数";
      default: return "微信服务异常，请稍后再试";
    }
  }



  private Date setSendTime(QwSopSettingTimeParam params) {
    Date currentTime = new Date();
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(currentTime);

    try {
      if (params.getType() == 1) {
        int hourToAdd = Integer.parseInt(params.getHour());
        int minuteToAdd = Integer.parseInt(params.getMinute());
        calendar.add(Calendar.HOUR, hourToAdd);
        calendar.add(Calendar.MINUTE, minuteToAdd);
      } else if (params.getType() == 2) {
        calendar.add(Calendar.DAY_OF_MONTH, Integer.parseInt(params.getDay()));
        SimpleDateFormat timeFormatter = new SimpleDateFormat("HH:mm");
        Date parsedTime = timeFormatter.parse(params.getTime());
        Calendar timeCalendar = Calendar.getInstance();
        timeCalendar.setTime(parsedTime);
        calendar.set(Calendar.HOUR_OF_DAY, timeCalendar.get(Calendar.HOUR_OF_DAY));
        calendar.set(Calendar.MINUTE, timeCalendar.get(Calendar.MINUTE));
        calendar.set(Calendar.SECOND, 0);
      }
    } catch (Exception e) {
      e.printStackTrace(); // 或者更好的异常处理
    }

    return calendar.getTime();
  }
    @GetMapping("/getWxConfig")
    @Synchronized
    public R getWxConfig(@RequestParam String url) throws WxErrorException {
      try {
        String sLink = URLDecoder.decode(url, "UTF-8");
        final WxJsapiSignature jsapiSignature = wxMpService.createJsapiSignature(sLink);
        return R.ok().put("data", jsapiSignature);
      } catch (UnsupportedEncodingException e) {
        // URL解码异常
        return R.error(e.getMessage());
      }

    }
}
