package org.springblade.modules.auth.endpoint;


import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springblade.auth.enums.ThirdPartyLoginType;
import org.springblade.common.cache.CacheNames;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.constant.AppConstant;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.secure.utils.WebUtil;
import org.springblade.core.tool.exception.ServiceException;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.auth.enums.UserEnum;
import org.springblade.modules.auth.provider.ITokenGranter;
import org.springblade.modules.auth.provider.TokenGranterBuilder;
import org.springblade.modules.auth.provider.TokenParameter;
import org.springblade.modules.auth.service.BladeMicroAppTokenService;
import org.springblade.modules.auth.utils.TokenUtil;
import org.springblade.modules.system.entity.*;
import org.springblade.modules.system.service.ITenantService;
import org.springblade.modules.system.service.IThirdBindCountRecordService;
import org.springblade.modules.system.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.time.Duration;
import java.util.UUID;

@RestController
@RequestMapping(AppConstant.APPLICATION_AUTH_NAME+"/micro-app")
@Api(value = "微信小程序授权认证", tags = "微信小程序授权接口")
@Slf4j
public class BladeMicroAppTokenEndPoint extends BladeController {

    @Autowired
    private BladeMicroAppTokenService bladeMicroAppTokenService;

    @Autowired
    private BladeRedis bladeRedis;

    @Autowired
    private IUserService userService;

    @Autowired
    private IThirdBindCountRecordService thirdBindCountRecordService;

    @PostMapping("/login")
    @ApiOperation(value = "微信小程序登录", notes = "传入CODE")
    public Kv login(@ApiParam(value = "code", required = true) @RequestParam String code){

        Kv authInfo = Kv.create();
        JSONObject jsonObject = bladeMicroAppTokenService.getSessionKeyOrOpenId(code);
        if(!jsonObject.containsKey("errcode") || jsonObject.getInt("errcode") != 0) {
            return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_description", "获取OEPNID失败");
        }
        String openId = jsonObject.getStr("openid");
        String unionid = jsonObject.getStr("unionid");
        if(StrUtil.isEmpty(openId)) {
            return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_description", "无效的CODE");
        }
        ThirdBindCountRecord countRecord = thirdBindCountRecordService.getOne(Wrappers.<ThirdBindCountRecord>lambdaQuery()
                .eq(ThirdBindCountRecord::getMicroAppOpenId, openId));

        if (countRecord == null){ // 如果没有查询到绑定记录
            // 保存接口
            String openIdKey = UUID.randomUUID().toString();
            if (StrUtil.isNotEmpty(unionid)){
                openId = openId + ";" + unionid;
            }
            bladeRedis.setEx(CacheNames.MICRO_OPENID_UNIONID + openIdKey, openId, Duration.ofMinutes(30));
            return authInfo.set("error_code", HttpServletResponse.SC_NO_CONTENT)
                    .set("openIdKey",openIdKey)
                    .set("error_msg", "用户不存在...");
        } else {
            // 如果unionid不为空且数据库为空则更新
            if (StrUtil.isEmpty(countRecord.getMicroAppUnionId()) && StrUtil.isNotEmpty(unionid)){
                countRecord.setMicroAppUnionId(unionid);
                thirdBindCountRecordService.updateById(countRecord);
            }
            UserInfo userInfo = bladeMicroAppTokenService.grant(userService.getById(countRecord.getUserId()));

            if (userInfo == null || userInfo.getUser() == null) {
                return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "用户名或密码不正确");
            }

            if (Func.isEmpty(userInfo.getRoles())) {
                return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "未获得用户的角色信息");
            }

            return TokenUtil.createAuthInfo(userInfo);
        }
    }

    @PostMapping("/bind/openid")
    @ApiOperation(value = "绑定租户三方账号，并获取令牌", notes = "传入租户ID:tenantId,账号:account,密码:password," +
            "三方登录的KEY:header['openId-Key']")
    public Kv bindOpenId(@ApiParam(value = "租户ID", required = true) @RequestParam String tenantId,
                         @ApiParam(value = "账号", required = true) @RequestParam(required = false) String username,
                         @ApiParam(value = "密码", required = true) @RequestParam(required = false) String password){
        log.info("绑定三方账户开始了.....");
        Kv authInfo = Kv.create();

        String grantType = WebUtil.getRequest().getParameter("grant_type");
        String openIdKey = WebUtil.getRequest().getHeader(TokenUtil.OPENID_KEY);
        log.info("前端传递的openIdKey: "+openIdKey);

        String userType = Func.toStr(WebUtil.getRequest().getHeader(TokenUtil.USER_TYPE_HEADER_KEY), TokenUtil.DEFAULT_USER_TYPE);

        TokenParameter tokenParameter = new TokenParameter();
        tokenParameter.getArgs().set("tenantId", tenantId).set("username", username).set("password", password).set("grantType", grantType).set("userType", userType);

        ITokenGranter granter = TokenGranterBuilder.getGranter(grantType);
        UserInfo userInfo = granter.grant(tokenParameter);

        if (userInfo == null || userInfo.getUser() == null) {
            return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_description", "用户名或密码不正确");
        }

        if (userInfo.getUser().getIsLogin() == 1) {
            return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_description", "该用户不能使用账号密码登录");
        }

        if (Func.isEmpty(userInfo.getRoles())) {
            return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_description", "未获得用户的角色信息");
        }

        String openId = bladeRedis.get(CacheNames.MICRO_OPENID_UNIONID + openIdKey);
        log.info("获取缓存的openId：key："+CacheNames.MICRO_OPENID_UNIONID + openIdKey+" value: "+openId);
        User user = userInfo.getUser();
        ThirdBindCountRecord countRecord = thirdBindCountRecordService.getOne(Wrappers.<ThirdBindCountRecord>lambdaQuery()
                .eq(ThirdBindCountRecord::getUserId, user.getId()));
        boolean isBind = false;
        if (countRecord != null){
            if (StrUtil.isEmpty(countRecord.getMicroAppOpenId())) {
                String[] split = openId.split(";");
                countRecord.setMicroAppOpenId(split[0]);
                if (StrUtil.isNotEmpty(split[1])){
                    countRecord.setMicroAppUnionId(split[1]);
                }
                // 更新追加绑定小程序
                isBind = thirdBindCountRecordService.updateById(countRecord);
            }
        } else {
            // 绑定三方账号
            ThirdBindCountRecord record = new ThirdBindCountRecord();
            String[] split = openId.split(";");
            record.setMicroAppOpenId(split[0]);
            if (StrUtil.isNotEmpty(split[1])) {
                record.setMicroAppUnionId(split[1]);
            }
            // 新增绑定小程序app
            isBind = thirdBindCountRecordService.save(record);
        }
        // 校验登录方式是否被允许
        if (isBind){
            log.info("账户绑定成功...");
            bladeRedis.del(CacheNames.THIRD_OPENID + openIdKey);
            return TokenUtil.createAuthInfo(userInfo);
        } else {
            log.info("账户绑定失败");
            return authInfo.set("error_code", HttpServletResponse.SC_RESET_CONTENT).set("error_description", "重复绑定...");
        }
    }

    @PostMapping("/unBind")
    @ApiOperation("解绑小程序账号")
    public Kv unBindThirdCount(){
        if (getUser() == null){
            throw new ServiceException("请先登录再解除绑定");
        }
        ThirdBindCountRecord countRecord = new ThirdBindCountRecord();
        countRecord.setUserId(getUser().getUserId());
        countRecord.setMicroAppUnionId("");
        countRecord.setMicroAppOpenId("");
        boolean unBind = thirdBindCountRecordService.update(countRecord,
                Wrappers.<ThirdBindCountRecord>lambdaUpdate()
                        .eq(ThirdBindCountRecord::getUserId,getUser().getUserId()));
        if (unBind) {
            return Kv.create().set("ok", "解绑成功");
        } else {
            return Kv.create().set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_description", "解绑失败");
        }
    }
}
