package com.ylx.web.controller.massage;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ylx.common.annotation.Log;
import com.ylx.common.constant.Constants;
import com.ylx.common.core.controller.BaseController;
import com.ylx.common.core.domain.AjaxResult;
import com.ylx.common.core.domain.R;
import com.ylx.common.core.domain.model.WxLoginUser;
import com.ylx.common.enums.BusinessType;
import com.ylx.common.utils.MessageUtils;
import com.ylx.common.utils.file.FileUploadUtils;
import com.ylx.framework.config.ServerConfig;
import com.ylx.framework.manager.AsyncManager;
import com.ylx.framework.manager.factory.AsyncFactory;
import com.ylx.framework.web.service.WxTokenService;
import com.ylx.massage.domain.TWxUser;
import com.ylx.massage.domain.dto.QueryWxUserDTO;
import com.ylx.massage.domain.vo.TWxUserVo;
import com.ylx.coupon.service.CouponReceiveService;
import com.ylx.massage.service.TWxUserService;
import com.ylx.massage.service.TbFileService;
import com.ylx.massage.utils.WxQrCodeUtil;
import com.ylx.massage.utils.WxUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author : YJR
 * @className : WxController
 * @description : [描述说明该类的功能]
 * @createTime : 2023/6/27 19:44
 */
@RestController
@Api(tags = {"微信"})
@RequestMapping("/wx")
@Slf4j
public class WxController extends BaseController {
    @Resource
    private WxUtil wxUtil;

    @Autowired
    private ServerConfig serverConfig;


    @Resource
    private WxQrCodeUtil wxQrCodeUtil;
    @Resource
    private TWxUserService wxUserService;

    @Resource
    private WxTokenService wxTokenService;

    @Autowired
    private WxMaService wxMaService;

    @Autowired
    private TbFileService tbFileService;

    @Autowired
    private CouponReceiveService couponReceiveService;

    @Resource(name = "commonAsyncExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    /**
     * 获取二维码
     *
     * @param inviteUserId
     * @return AjaxResult
     */
    @ApiOperation("获取二维码")
    @PostMapping(value="getwxQrCode")
    public AjaxResult inviteCode(@RequestParam ("inviteUserId")String inviteUserId) throws WxErrorException, IOException {
        File file = wxMaService.getQrcodeService().createWxaCodeUnlimit(inviteUserId, null, 300, true, null, true);
        MultipartFile multipartFile = FileUploadUtils.getMultipartFile(file);
        return tbFileService.uploadFile(multipartFile);
    }

    /**
     * 小程序登录
     *
     * @param wxLoginUser
     * @return
     */
    @PostMapping("v0/login")
    @ApiOperation("小程序登录不用")
    public AjaxResult login(@RequestBody WxLoginUser wxLoginUser) {
        AjaxResult ajax = new AjaxResult();
        try {
            // 验证输入数据的合法性
            if (wxLoginUser == null || wxLoginUser.getCode() == null || wxLoginUser.getCode().isEmpty()) {
                return AjaxResult.error("输入数据不合法");
            }

            //todo 获取用户信息自测方法
            WxLoginUser wxUser = wxUtil.getUserOpenId(wxLoginUser.getCode());
            if (wxUser == null) {
                return AjaxResult.error("获取用户信息失败");
            }

            // 生成并返回令牌
            String token = wxTokenService.createToken(wxUser);
            if (token == null || token.isEmpty()) {
                return AjaxResult.error("生成令牌失败");
            }

            ajax.put(Constants.TOKEN, token);
            return ajax;
        } catch (Exception e) {
            // 捕获并处理异常，返回友好的错误信息
            JSONObject errorObj = new JSONObject();
            errorObj.put("message", "操作失败");
            errorObj.put("error", e.getMessage());
            return AjaxResult.error(JSON.toJSONString(errorObj));
        }
    }

    /**
     * 获取电话号
     *
     * @param param
     * @return
     */
    @ApiOperation("获取电话号")
    @RequestMapping(value = "getPhone", method = RequestMethod.POST)
    public R getPhone(@RequestBody JSONObject param) {
        String code = param.getString("code");
        String openId = param.getString("openId");
        if (StringUtils.isBlank(code)) {
            return R.fail("openId或者授权conde为空");
        }
        String phone = wxUtil.getUserPhone(openId, code);
        if (StringUtils.isBlank(phone)) {
            return R.fail("获取手机号信息失败,请重试");
        }
        return R.ok(phone);
    }

    /**
     * 获取用户信息
     *
     * @param
     * @return
     */
    @ApiOperation("获取用户信息")
    @Log(title = "获取用户信息", businessType = BusinessType.OTHER)
    @RequestMapping(value = "getUserInfo", method = RequestMethod.GET)
    public R getUserInfo() {
        WxLoginUser wxLoginUser = getWxLoginUser();
        // 检查wxLoginUser是否为null
        if (wxLoginUser == null) {
            return R.fail("用户登录信息不存在");
        }
        LambdaQueryWrapper<TWxUser> queryWrapper = new LambdaQueryWrapper<TWxUser>()
                .eq(TWxUser::getcOpenid, wxLoginUser.getCOpenid());
        TWxUser wxUser;
        try {
            wxUser = wxUserService.getOne(queryWrapper);
        } catch (Exception e) {
            log.error("获取用户信息失败", e);
            return R.fail("获取用户信息失败，系统异常");
        }
        if (wxUser == null) {
            return R.fail("用户信息不存在");
        }
        // 移除用户登录的session key
        wxUser.setcSessionKey(null);
        return R.ok(wxUser);
    }


    /**
     * 获取用户信息
     *
     * @param param
     * @return
     */
    @RequestMapping(value = "getUser", method = RequestMethod.POST)
    public List<TWxUser> getUser(@RequestBody JSONObject param) {
        QueryWrapper<TWxUser> wrapper = new QueryWrapper<>();
        return wxUserService.list(wrapper);
    }

    @RequestMapping(value = "select", method = RequestMethod.GET)
    public R select(Page<TWxUser> page, TWxUser user) {
        LambdaQueryWrapper<TWxUser> objectLambdaQueryWrapper = new LambdaQueryWrapper<>();
        objectLambdaQueryWrapper.eq(StringUtils.isNotBlank(user.getcOpenid()), TWxUser::getcOpenid, user.getcOpenid()).
                like(StringUtils.isNotBlank(user.getcNickName()), TWxUser::getcNickName, user.getcNickName());
        // 获取查询返回结果
        Page<TWxUser> pageSelect = wxUserService.page(page, objectLambdaQueryWrapper);
        return R.ok(pageSelect);
    }

    /**
     * 登录接口
     * @param code
     * @param encryptedData
     * @param iv
     * @param parentOpenId
     * @return R<Object>
     */
    @ApiOperation("小程序登录")
    @Log(title = "小程序登录", businessType = BusinessType.OTHER)
    @PostMapping("/login")
    public R<Object> login(@RequestParam("code") String code, @RequestParam("encryptedData") String encryptedData,
                           @RequestParam("iv") String iv, @RequestParam(required = false, value = "parentOpenId") String parentOpenId) {
        try {
            // 调用微信 API 获取用户的 openid 和 session_key
            WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(code);
            String openid = session.getOpenid();

            // 调用微信 API 获取用户的手机号
            WxMaPhoneNumberInfo phoneInfo = wxMaService.getUserService().getPhoneNoInfo(session.getSessionKey(), encryptedData, iv);
            String phoneNumber = phoneInfo.getPhoneNumber();

            // 调用微信 API 获取用户的详细信息
            WxMaUserInfo userInfo = wxMaService.getUserService().getUserInfo(session.getSessionKey(), encryptedData, iv);
            // 获取用户昵称
            String nickName = userInfo.getNickName();
            // 获取用户头像
            String avatarUrl = userInfo.getAvatarUrl();
            // 获取用户国家
            String country = userInfo.getCountry();
            // 获取用户省份
            String province = userInfo.getProvince();
            // 获取用户城市
            String city = userInfo.getCity();

            // 将用户信息保存到数据库中
            LambdaQueryWrapper<TWxUser> objectLambdaQueryWrapper = new LambdaQueryWrapper<>();
            objectLambdaQueryWrapper.eq(TWxUser::getcOpenid, openid);
            TWxUser user = wxUserService.getOne(objectLambdaQueryWrapper);
            if (user == null) {
                BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
                user = new TWxUser();
                user.setcOpenid(openid);
                user.setcNickName(nickName);
                user.setcIcon(avatarUrl);
                user.setcPhone(phoneNumber);
                user.setCPassword(encoder.encode("123456")) ;
                wxUserService.save(user);
                //异步 添加新人优惠卷
                TWxUser finalUser = user;
//                threadPoolTaskExecutor.submit(() -> couponReceiveService.submit(new CouponReceive().setOpenid(finalUser.getcOpenid()).setCouponId("1")));
                user.setId(user.getId());
            }

            WxLoginUser wxUser = new WxLoginUser();
            BeanUtils.copyProperties(user, wxUser);
            // 生成并返回令牌
            String token = wxTokenService.createToken(wxUser);
            if (token == null || token.isEmpty()) {
                return R.fail("生成令牌失败");
            }
            wxUser.setToken(token);
            // 返回用户信息
            // 记录登录信息
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(wxUser.getCOpenid(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
            return R.ok(wxUser);
        } catch (WxErrorException e) {
            log.error("登录失败：" + e.getMessage(), e);
            return R.fail("登录失败：" + e.getMessage());
        }
    }




    /**
     * 更新用户信息接口
     */
    @PostMapping("/update")
    public R updateUserInfo(@RequestBody TWxUser user) {
        try {
            // 前端校验后，再次进行后端的基础校验
            if (user == null || user.getcOpenid() == null || user.getcOpenid().isEmpty()) {
                return R.fail("用户信息不能为空");
            }
            // 保存或更新用户信息
            if (wxUserService.saveOrUpdate(user)) {
                return R.ok("用户信息更新成功");
            } else {
                return R.fail("更新用户信息失败");
            }
        } catch (Exception e) {
            // 异常处理，记录日志并返回友好的错误信息
            log.error("更新用户信息异常", e);
            return R.fail("更新用户信息异常，请稍后尝试");
        }
    }

    /**
     * 获取微信用户手机号
     *
     * @param code code值
     */
    public String getMobilePhoneByWeixin(String code) {
        try {

            String accessToken = wxMaService.getAccessToken();
            String url = UrlBuilder
                    .of("https://api.weixin.qq.com/wxa/business/getuserphonenumber")
                    .addQuery("access_token", accessToken)
                    .build();
            Map<String, Object> paramBody = new HashMap<>(2);
            paramBody.put("code", code);
            String result = HttpUtil.post(url, JSON.toJSONString(paramBody));
            JSONObject jsonObject = JSONObject.from(JSON.parseObject(result));
            if ("40029".equals(jsonObject.getString("errcode"))) {
                throw new RuntimeException("code无效");
            }

            if ("-1".equals(jsonObject.getString("errcode"))) {
                throw new RuntimeException("微信系统繁忙");
            }
            JSONObject phoneInfo = jsonObject.getJSONObject("phone_info");
            return phoneInfo.getString("phoneNumber");
        } catch (WxErrorException e) {
            e.printStackTrace();
            throw new RuntimeException("获取手机号失败");
        }
    }

    /**
     * 查询微信用户列表
     *
     * @param page 分页参数
     * @param user
     * @return R<Page<TWxUserVo>> 微信用户列表
     */
    @GetMapping("pc/getUserList")
    @ApiOperation("查询微信用户列表")
    public R<Page<TWxUserVo>> getUserList(Page<TWxUserVo> page, QueryWxUserDTO queryWxUserDTO) {
        try {
            return R.ok(wxUserService.getUserList(page, queryWxUserDTO));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}
