package com.njzscloud.common.security.handler;

import com.njzscloud.common.core.ex.ExceptionMsg;
import com.njzscloud.common.core.jackson.Jackson;
import com.njzscloud.common.core.utils.Mime;
import com.njzscloud.common.core.utils.R;
import com.njzscloud.common.mvc.util.ServletUtil;
import com.njzscloud.common.security.contant.AuthWay;
import com.njzscloud.common.security.ex.UserLoginException;
import com.njzscloud.common.security.support.AuthenticationDetails;
import com.njzscloud.common.security.support.LoginHistory;
import com.njzscloud.common.security.support.LoginHistoryRecorder;
import com.njzscloud.common.security.support.UserDetail;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.concurrent.CompletableFuture;

/**
 * 登陆后置处理器
 */
@Slf4j
@RequiredArgsConstructor
public class LoginPostHandler implements AuthenticationSuccessHandler, AuthenticationFailureHandler {

    private final LoginHistoryRecorder loginHistoryRecorder;

    /**
     * 登陆失败
     */
    @Override
    public void onAuthenticationFailure(HttpServletRequest request,
                                        HttpServletResponse response,
                                        AuthenticationException exception) throws IOException, ServletException {
        log.error("登录失败", exception);
        R<?> r;
        if (exception instanceof UserLoginException) {
            r = R.failed(((UserLoginException) exception).msg, exception.getMessage());
        } else if (exception instanceof UsernameNotFoundException) {
            r = R.failed(ExceptionMsg.CLI_ERR_MSG, "账号或密码错误");
        } else {
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            r = R.failed(ExceptionMsg.SYS_ERR_MSG, "无法进行用户校验");
        }
        ServletUtil.write(response, Jackson.toJsonStr(r), Mime.u8Val(Mime.JSON));
    }

    /**
     * 登陆成功
     */
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {
        R<?> r = R.success(authentication.getPrincipal());
        ServletUtil.write(response, Jackson.toJsonStr(r), Mime.u8Val(Mime.JSON));
    }

    /**
     * 记录登陆日志
     *
     * @param authentication 已认证的认证对象
     */
    public void recordLoginHistory(Authentication authentication) {
        AuthenticationDetails details = (AuthenticationDetails) authentication.getDetails();
        UserDetail userDetail = (UserDetail) authentication.getPrincipal();
        AuthWay authWay = userDetail.getAuthWay();

        long userAccountId = userDetail.getAccountId();
        long userId = userDetail.getUserId();
        LocalDateTime now = LocalDateTime.now();
        LoginHistory loginHistory = new LoginHistory()
            .setUserId(userId)
            .setAccountId(userAccountId)
            .setLoginTime(now)
            .setAuthWay(authWay)
            .setIp(details.getRemoteAddress())
            .setUserAgent(details.getUserAgent());
        CompletableFuture.runAsync(() -> {
            try {
                loginHistoryRecorder.record(loginHistory);
            } catch (Throwable e) {
                log.error("登录日志记录失败", e);
            }
        });
    }
}
