package com.yida.data.auth.controller;

import com.yida.data.auth.entity.BindUser;
import com.yida.data.auth.service.SocialLoginService;
import com.yida.data.common.core.common.ModuleName;
import com.yida.data.common.core.common.ResultBean;
import com.yida.data.common.core.entity.FebsResponse;
import com.yida.data.common.core.entity.constant.StringConstant;
import com.yida.data.common.core.entity.system.UserConnection;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.FebsUtil;
import com.yida.data.log.annotation.OperationLog;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * @author MrBird
 */
@Slf4j
@Controller
@RefreshScope
@RequiredArgsConstructor
@RequestMapping("social")
public class SocialLoginController {

    private static final String TYPE_LOGIN = "login";
    private static final String TYPE_BIND = "bind";

    private final SocialLoginService socialLoginService;
    @Value("${febs.frontUrl}")
    private String frontUrl;


    /**
     * 登录
     *
     * @param oauthType 第三方登录类型
     * @param response  response
     */
    @ResponseBody
    @GetMapping("/login/{oauthType}/{type}")
    public void renderAuth(@PathVariable String oauthType, @PathVariable String type, HttpServletResponse response)
            throws IOException, FebsException {
        AuthRequest authRequest = socialLoginService.renderAuth(oauthType);
        response.sendRedirect(
                authRequest.authorize(oauthType + StringConstant.DOUBLE_COLON + AuthStateUtils.createState()) + "::"
                        + type);
    }

    /**
     * 登录成功后的回调
     *
     * @param oauthType 第三方登录类型
     * @param callback  携带返回的信息
     * @return String
     */
    @GetMapping("/{oauthType}/callback")
    public String login(@PathVariable String oauthType, AuthCallback callback, String state, Model model) {
        try {
            FebsResponse febsResponse = null;
            String type = StringUtils.substringAfterLast(state, StringConstant.DOUBLE_COLON);
            if (StringUtils.equals(type, TYPE_BIND)) {
                febsResponse = socialLoginService.resolveBind(oauthType, callback);
            } else {
                febsResponse = socialLoginService.resolveLogin(oauthType, callback);
            }
            model.addAttribute("response", febsResponse);
            model.addAttribute("frontUrl", frontUrl);
            return "result";
        } catch (Exception e) {
            String errorMessage = FebsUtil.containChinese(e.getMessage()) ? e.getMessage() : "第三方登录失败";
            model.addAttribute("error", e.getMessage());
            return "fail";
        }
    }

    /**
     * 绑定并登录
     *
     * @param bindUser bindUser
     * @param authUser authUser
     * @return FebsResponse
     */
    @ResponseBody
    @PostMapping("bind/login")
    public FebsResponse bindLogin(@Valid BindUser bindUser, AuthUser authUser) throws FebsException {
        OAuth2AccessToken oAuth2AccessToken = this.socialLoginService.bindLogin(bindUser, authUser);
        return new FebsResponse().data(oAuth2AccessToken);
    }

    /**
     * 注册并登录
     *
     * @param registUser registUser
     * @param authUser   authUser
     * @return FebsResponse
     */
    @ResponseBody
    @PostMapping("sign/login")
    public FebsResponse signLogin(@Valid BindUser registUser, AuthUser authUser) throws FebsException {
        OAuth2AccessToken oAuth2AccessToken = this.socialLoginService.signLogin(registUser, authUser);
        return new FebsResponse().data(oAuth2AccessToken);
    }

    /**
     * 绑定
     *
     * @param bindUser bindUser
     * @param authUser authUser
     */
    @ResponseBody
    @PostMapping("bind")
    public void bind(BindUser bindUser, AuthUser authUser) throws FebsException {
        this.socialLoginService.bind(bindUser, authUser);
    }

    /**
     * 解绑
     *
     * @param bindUser  bindUser
     * @param oauthType oauthType
     */
    @ResponseBody
    @DeleteMapping("unbind")
    public void unbind(BindUser bindUser, String oauthType) throws FebsException {
        this.socialLoginService.unbind(bindUser, oauthType);
    }

    /**
     * 根据用户名获取绑定关系
     *
     * @param username 用户名
     * @return FebsResponse
     */
    @ResponseBody
    @GetMapping("connections/{username}")
    public FebsResponse findUserConnections(@NotBlank(message = "{required}") @PathVariable String username) {
        List<UserConnection> userConnections = this.socialLoginService.findUserConnections(username);
        return new FebsResponse().data(userConnections);
    }

    /**
     * 企业微信用户授权登录回调
     */
    @ResponseBody
    @GetMapping("qywx/login")
    @OperationLog(module = ModuleName.AUTH, methods = "企业微信登录")
    public FebsResponse qywxLogin(String code, String state, String corpId,
                                  @ApiParam("0-教师，1-家长") Integer type) {
        return new FebsResponse().data(socialLoginService.qywxLogin(code, state, corpId, type));
    }

    @ResponseBody
    @GetMapping("app/login")
    //@OperationLog(module = ModuleName.AUTH, methods = "app登录")
    public FebsResponse appLogin(@ApiParam("区域id，app") String areaId,
                                 @ApiParam("学校Id") Long schoolId,
                                 @ApiParam("手机号") String mobile,
                                 @ApiParam("app用户id") String userId,
                                 @ApiParam("0-教师，1-家长") Integer type) {
        return new FebsResponse().data(socialLoginService.appLogin(areaId, schoolId, mobile, userId, type));
    }

    @ResponseBody
    @GetMapping("wxpublic/login")
    //@OperationLog(module = ModuleName.AUTH, methods = "app登录")
    public FebsResponse wxpublicLogin(String code, String appId,
                                      @ApiParam("0-教师，1-家长") Integer type,
                                      Long schoolId, String mobile) {
        return new FebsResponse().data(socialLoginService.wxpublicLogin(code, appId, type, schoolId, mobile));
    }

    /**
     * h5登录
     *
     * @param schoolId 学校Id
     * @param mobile   手机号
     * @param type     0-教师，1-家长
     * @return com.yida.data.common.core.entity.FebsResponse
     * @author ZYJ
     * @date 2022/9/19 17:25
     */
    @ResponseBody
    @GetMapping("h5/login")
    public FebsResponse h5Login(@ApiParam("学校Id") Long schoolId, @ApiParam("手机号") String mobile,
                                @ApiParam("0-教师，1-家长") Integer type) {
        return new FebsResponse().data(socialLoginService.h5Login(schoolId, mobile, type));
    }

    @ResponseBody
    @ApiOperation("检查openId状态")
    @GetMapping("smart/checkOpenId")
    public ResultBean<Map<String, Object>> checkOpenId(@RequestParam @ApiParam(value = "微信公众号授权code", required = true) String code,
                                       @RequestParam @ApiParam(value = "学校id(链接上附带)", required = true) Long deptId) {
        return ResultBean.buildSuccess(socialLoginService.checkOpenId(code, deptId));
    }

    @ResponseBody
    @ApiOperation("智慧迎新学生端登录接口")
    @GetMapping("wxPublic/welcome/login")
    public FebsResponse wxPublicLogin(@RequestParam @ApiParam(value = "微信openId", required = true) String openId,
                                      @RequestParam @ApiParam(value = "学校id(链接上附带)", required = true) Long deptId) {
        return new FebsResponse().data(socialLoginService.wxPublicLogin(openId, deptId));
    }
}
