package cn.reghao.tnb.auth.app.security.handler;

import cn.reghao.tnb.auth.app.model.vo.LoginAccount;
import cn.reghao.tnb.common.web.WebResult;
import cn.reghao.tnb.common.web.ServletUtil;
import cn.reghao.tnb.auth.api.iface.AccountQuery;
import cn.reghao.tnb.auth.app.db.repository.AccountRepository;
import cn.reghao.tnb.auth.app.model.constant.LoginPlat;
import cn.reghao.tnb.auth.app.model.vo.AccountLoginRet;
import cn.reghao.tnb.auth.app.model.vo.AccountToken;
import cn.reghao.tnb.auth.app.security.form.AccountAuthToken;
import cn.reghao.tnb.auth.app.service.AccountTokenService;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.stereotype.Component;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 认证成功后的处理
 *
 * @author reghao
 * @date 2022-07-08 14:02:34
 */
@Component
public class AuthSuccessHandlerImpl implements AuthenticationSuccessHandler {
    private final AccountRepository accountRepository;
    private final AccountTokenService accountTokenService;
    private final AccountQuery accountQuery;

    public AuthSuccessHandlerImpl(AccountRepository accountRepository, AccountTokenService accountTokenService,
                                  AccountQuery accountQuery) {
        this.accountRepository = accountRepository;
        this.accountTokenService = accountTokenService;
        this.accountQuery = accountQuery;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication auth)
            throws IOException, ServletException {
        AccountAuthToken authToken = (AccountAuthToken) auth;
        loginSuccess(authToken, response);
    }

    public void loginSuccess(AccountAuthToken authToken, HttpServletResponse response) throws IOException {
        long userId = authToken.getUserId();
        String loginId = authToken.getLoginId();
        int loginType = authToken.getLoginType();
        int plat = authToken.getPlat();
        boolean rememberMe = authToken.isRememberMe();
        String redirectPath = getRedirectPath();
        long timeout = rememberMe ? 3600*24*30 : 0;
        String uri = ServletUtil.getRequest().getRequestURI();
        if (uri.startsWith("/oauth/redirect")) {
            // 使用第三方帐号的 oauth 方式登入
            accountTokenService.setCookie(authToken, timeout);
            response.sendRedirect(redirectPath);
            return;
        }

        AccountLoginRet accountLoginRet = new AccountLoginRet(redirectPath);
        if (LoginPlat.rest.getValue() == plat) {
            LoginAccount loginAccount = accountRepository.getLoginAccount(userId);
            String userIdStr = accountQuery.getUserIdStr(loginAccount.getUserId());
            loginAccount.setUserIdStr(userIdStr);
            AccountToken accountToken = accountTokenService.grantUserToken(authToken);
            accountLoginRet = new AccountLoginRet(loginAccount, accountToken, redirectPath);
        } else if (LoginPlat.web.getValue() == plat) {
            accountTokenService.setCookie(authToken, timeout);
            String userIdStr = accountQuery.getUserIdStr(userId);
            accountLoginRet = new AccountLoginRet(userIdStr, loginId, plat, redirectPath);
        }

        String body = WebResult.success(accountLoginRet);
        writeResponse(response, body);
    }

    /**
     * 认证成功后, 重定向到登入前的地址, 需要 session 的支持
     *
     * @param
     * @return
     * @date 2023-08-16 10:58:41
     */
    private String getRedirectPath() {
        String redirectPath = "/";
        // 获取 spring security 在 session 中存放的变量
        SavedRequest savedRequest =
                (SavedRequest) ServletUtil.getSession().getAttribute("SPRING_SECURITY_SAVED_REQUEST");
        if (savedRequest != null) {
            String redirectUrl = savedRequest.getRedirectUrl();
            redirectPath = redirectUrl;
        }
        return redirectPath;
    }

    private void writeResponse(HttpServletResponse response, String body) throws IOException {
        response.setContentType("application/json; charset=utf-8");
        PrintWriter printWriter = response.getWriter();
        printWriter.write(body);
    }
}
