package cn.ey.biz.module.system.controller.admin.auth;

import cn.ey.biz.common.pojo.R;
import cn.ey.biz.framework.operatelog.core.annotations.OperateLog;
import cn.ey.biz.framework.security.config.SecurityProperties;
import cn.ey.biz.framework.third.auth.config.JustAuthProperties;
import cn.ey.biz.module.system.controller.admin.auth.vo.AuthLoginRespVO;
import cn.ey.biz.module.system.controller.admin.auth.vo.ThirdAuthCallBackReqVO;
import cn.ey.biz.module.system.controller.admin.auth.vo.ThirdAuthLoginReqVO;
import cn.ey.biz.module.system.service.auth.AdminAuthService;
import cn.ey.biz.module.system.service.auth.ThirdAuthService;
import cn.hutool.core.util.StrUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import static cn.ey.biz.common.pojo.R.success;
import static cn.ey.biz.framework.security.core.util.SecurityFrameworkUtils.obtainAuthorization;

@Api(tags = "管理后台 - 第三方认证")
@RestController
@RequestMapping("/system/third-auth")
@Validated
@Slf4j
public class ThirdAuthController {

    @Resource
    private AdminAuthService authService;
    @Resource
    private ThirdAuthService thirdAuthService;
    @Resource
    private JustAuthProperties properties;
    @Resource
    private SecurityProperties securityProperties;

    @PostMapping("/login")
    @PermitAll
    @ApiOperation("第三方登录")
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public R<AuthLoginRespVO> login(@RequestBody @Valid ThirdAuthLoginReqVO reqVO) {
        // 如果是 Token 置换的场景
        if (properties.isDisplace()) {
            return success(thirdAuthService.login03(reqVO));
        } else {
            return success(thirdAuthService.login02(reqVO));
        }
    }

    @PostMapping("/login-other")
    @PermitAll
    @ApiOperation("第三方登录")
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public R<AuthLoginRespVO> loginOther(@RequestBody @Valid ThirdAuthLoginReqVO reqVO) {
        return success(thirdAuthService.login03(reqVO));
    }

    @SneakyThrows
    @PostMapping("/{platform}/login")
    @PermitAll
    @ApiOperation("第三方授权的登录接口")
    public R<AuthLoginRespVO> login(@PathVariable("platform") Integer platform,
                                    @RequestBody @Valid ThirdAuthCallBackReqVO reqVO) {
        return success(thirdAuthService.login(platform, reqVO));
    }

    @SneakyThrows
    @PostMapping("/{platform}/logout")
    @ApiOperation("第三方取消授权")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "platform", value = "第三方平台", required = true, dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "accessToken", value = "访问令牌", required = true, dataTypeClass = String.class)
    })
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public R<String> logout(@PathVariable("platform") Integer platform,
                            @RequestParam(value = "accessToken", required = false) String accessToken,
                            HttpServletRequest request,
                            HttpServletResponse response) {
        String token = obtainAuthorization(request, securityProperties.getTokenHeader());
        if (StrUtil.isNotBlank(token)) {
            accessToken = token;
        }
        return success(thirdAuthService.logout(platform, accessToken));
    }

    @SneakyThrows
    @PostMapping("/{platform}/logout/redirect")
    @ApiOperation("第三方取消授权")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "platform", value = "第三方平台", required = true, dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "accessToken", value = "访问令牌", dataTypeClass = String.class)
    })
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public void logoutRedirect(@PathVariable("platform") Integer platform,
                               @RequestParam(value = "accessToken", required = false) String accessToken,
                               HttpServletResponse response) {
        String redirect = thirdAuthService.logout(platform, accessToken);
        response.setStatus(302);
        response.sendRedirect(redirect);
    }

    @PostMapping("/{platform}/refresh-token")
    @PermitAll
    @ApiOperation("第三方刷新令牌换取Token")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "platform", value = "第三方平台", required = true, dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "refreshToken", value = "刷新令牌", required = true, dataTypeClass = String.class)
    })
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public R<AuthLoginRespVO> refreshToken(@PathVariable("platform") Integer platform,
                                           @RequestParam(value = "refreshToken", required = false) String refreshToken,
                                           @RequestBody(required = false) RefreshToken body) {
        // 如果报文体传值则从报文体获取
        if (body != null && StringUtils.hasLength(body.getRefreshToken())) {
            refreshToken = body.getRefreshToken();
        }

        // 如果是 Token 置换的场景
        if (properties.isDisplace()) {
            return success(authService.refreshToken(refreshToken));
        } else {
            return success(thirdAuthService.refreshToken(platform, refreshToken));
        }
    }

    @GetMapping("/{platform}/auth-redirect")
    @PermitAll
    @ApiOperation("获取第三方授权的跳转地址")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "platform", value = "第三方平台", required = true, dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "redirectUri", value = "回调路径", dataTypeClass = String.class)
    })
    public R<String> redirect(@PathVariable("platform") Integer platform,
                              @RequestParam(name = "redirectUri", required = false) String redirectUri,
                              @RequestParam(name = "app", required = false) String app) {
        return R.success(thirdAuthService.getAuthorizeUrl(platform, redirectUri, app));
    }

    @SneakyThrows
    @GetMapping("/{platform}/callback")
    @PermitAll
    @ApiOperation("第三方授权的回调接口")
    public void callback01(@PathVariable("platform") Integer platform,
                         @RequestParam("code") String code,
                         @RequestParam("state") String state,
                         HttpServletResponse response) {
        // 先缓存登录信息
        thirdAuthService.callback02(platform, code, state);
        // 回调对应的
        String app = state.split(StrUtil.DASHED)[0];
        response.sendRedirect(properties.getRedirectUri().get(app) + "?code=" + code + "&state=" + state);
    }

    @SneakyThrows
    @PostMapping("/{platform}/callback")
    @PermitAll
    @ApiOperation("第三方授权的回调接口")
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public void callback02(@PathVariable("platform") Integer platform,
                         @RequestParam("code") String code,
                         @RequestParam("state") String state,
                         HttpServletResponse response) {
        // 先缓存登录信息
        thirdAuthService.callback02(platform, code, state);
        // 回调对应的
        String app = state.split(StrUtil.DASHED)[0];
        response.sendRedirect(properties.getRedirectUri().get(app) + "?code=" + code + "&state=" + state);
    }

    @Data
    private static class RefreshToken {
        private String refreshToken;
    }

}
