package com.ywt.alipaympapi.web.controller;


import com.alibaba.fastjson.JSON;
import com.alipay.easysdk.base.oauth.models.AlipaySystemOauthTokenResponse;
import com.alipay.easysdk.factory.Factory;
import com.ywt.alipaympapi.core.utils.*;

import com.ywt.alipaympapi.models.BaseResponse;
import com.ywt.alipaympapi.models.BaseResponse2;
import com.ywt.alipaympapi.models.Constants;
import com.ywt.alipaympapi.models.auth.*;
import com.ywt.alipaympapi.service.AuthService;
import com.ywt.alipaympapi.web.interceptors.WebAppContext;
import com.ywt.core.exception.AppMessageException;
import com.ywt.gapi.user.BindAlipayUserInfoRequest;
import com.ywt.gapi.user.BindAlipayUserInfoResponse;
import com.ywt.gapi.user.UserServiceGrpc;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import redis.clients.jedis.JedisCommands;

import java.util.Map;

/**
 * @author Walker
 * Created on 2022/8/29
 */
@Slf4j
@RestController("/auth")
@RequestMapping({"/auth"})
public class AuthController {

    @Autowired
    private UserServiceGrpc.UserServiceBlockingStub userServiceBlockingStub;
    @Autowired
    private AuthService authService;
    @Autowired
    private JedisCommands jedisCommands;


    @RequestMapping(value = {"/bind"}, method = RequestMethod.POST)
    public @ResponseBody BaseResponse2<BindAlipayMpResp> bind(@RequestBody
                                                              BindAlipayMpReq reqData) {
        BaseResponse2<BindAlipayMpResp> baseResponse = new BaseResponse2<>();
        try {
            int terminal = reqData.getTerminal();
            String ip = WebAppContext.current().getIP();
            String ticket = reqData.getTicket();
            CheckUtil.ensureNotEmpty(ticket, "ticket 不能为空");
            AlipayMpCfg cfg = BizUtil.getCfg(terminal);
            // 获取用户信息
            GetAlipayUserInfoReq req = new GetAlipayUserInfoReq();
            req.setTicket(ticket);
            req.setAppId(cfg.getAppId());
            req.setSaasSecurityKey(cfg.getSaasSecurityKey());
            GetAlipayUserInfoResp resp = authService.getAlipayUserInfo(req);
            String alipayUid = Checker.getStringValue(resp.getAlipayUid());
            CheckUtil.ensureNotEmpty(alipayUid, "支付宝用户信息有误，alipayUid 为空");
            String avatar = Checker.getStringValue(resp.getAvatar());
            String realName = Checker.getStringValue(resp.getRealName());
            String nickName = Checker.getStringValue(resp.getNickName());
            String mobile = Checker.getStringValue(resp.getMobile());
            CheckUtil.ensureNotEmpty(mobile, "支付宝用户未绑定手机，请先前往支付宝个人中心绑定");
            int age = Checker.getIntegerValue(resp.getAge());
            String idCardNo = Checker.getStringValue(resp.getIdCardNo());
            BindAlipayUserInfoResponse response = userServiceBlockingStub.bindAlipayUserInfo(BindAlipayUserInfoRequest.newBuilder()
                    .setAlipayUid(alipayUid)
                    .setAvatar(avatar)
                    .setRealName(realName)
                    .setNickName(nickName)
                    .setMobile(mobile)
                    .setIdCardNo(idCardNo)
                    .setAge(age)
                    .setTerminal(terminal)
                    .setIp(ip)
                    .build());
            if (response.getCode() == BaseResponse.SUCCEED) {
                int userId = response.getUserId();
                BindAlipayMpResp r = new BindAlipayMpResp();
                r.setUserId(userId);
                r.setAlipayUid(alipayUid);
                r.setMobile(mobile);
                // 根据终端判断医院信息
                r.setHospitalId(BizUtil.getCurrentHospitalId());
                return baseResponse.succeed(r);
            }
            return baseResponse.failed(BaseResponse.APP_ERROR, response.getInfo());
        } catch (AppMessageException appMessageException) {
            return baseResponse.error(appMessageException.getMessage());
        } catch (Exception e) {
            log.error("AuthController#bind(reqData = {}): {}", reqData, e.getMessage(), e);
            return baseResponse.error(e.getMessage());
        }
    }

    /**
     * 小程序提交 authCode，服务端换取 accessToken 并存入 Redis
     */
    @RequestMapping(value = {"/submitAuthCode"}, method = RequestMethod.POST)
    public @ResponseBody com.ywt.model.BaseResponse submitAuthCode(@RequestBody SubmitAuthCodeReq reqData) {
        com.ywt.model.BaseResponse baseResponse = new com.ywt.model.BaseResponse();
        try {
            String authCode = reqData.getAuthCode();
            String alipayUid = reqData.getAlipayUid();
            String appId = reqData.getAppId();
            CheckUtil.ensureNotEmpty(authCode, "authCode 不能为空");
            CheckUtil.ensureNotEmpty(alipayUid, "alipayUid 不能为空");
            CheckUtil.ensureNotEmpty(appId, "appId 不能为空");
            // auth_code 和 access_token 的区别：https://opendocs.alipay.com/support/01rg6k
            // auth_code 作为换取 access_token 的票据，每次用户授权完成，回调地址中的 auth_code 将不一样，auth_code 只能使用一次，一天未被使用自动过期。
            String rk = String.format(Constants.RK_ACCESS_TOKEN, appId, alipayUid);
            int terminal = BizUtil.getAlipayMpCfgByAppId(appId).getTerminal();
            BizUtil.initAlipayEasySdk(terminal);
            AlipaySystemOauthTokenResponse response = Factory.Base.OAuth().getToken(authCode);
            log.info("AuthController#submitAuthCode(): {} 换取 token: {}", rk, JSON.toJSONString(response));
            String accessToken = response.getAccessToken();
            int expire = (int) (Checker.getLongValue(response.getExpiresIn()) / 1000);
            CheckUtil.ensureNotEmpty(accessToken, "获取 token 失败");
            jedisCommands.set(rk, accessToken);
            jedisCommands.expire(rk, expire);
            return baseResponse.succeed();
        } catch (AppMessageException appMessageException) {
            return baseResponse.error(appMessageException.getMessage());
        } catch (Exception e) {
            log.error("AuthController#submitAuthCode(): {}", e.getMessage(), e);
            return baseResponse.error(e.getMessage());
        }
    }

    @RequestMapping(value = {"/test"}, method = RequestMethod.POST)
    public @ResponseBody BaseResponse2<String> test(@RequestBody Map<String, String> data) {
        BaseResponse2<String> baseResponse = new BaseResponse2<>();
        try {
            return new BaseResponse2<>();
        } catch (Exception e) {
            log.error("AuthController#test(): {}", e.getMessage(), e);
            return baseResponse.error(e.getMessage());
        }
    }

}
