package kr.co.accura.wbx.spring.auth;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import kr.co.accura.wbx.spring.config.WbxSpringProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.time.LocalDateTime;

/**
 * Azure Entra ID (OIDC) 로그인 성공 핸들러
 * <p>
 * OAuth2 로그인 성공 → WBX 호환 JWT 발급 → 프론트엔드 콜백 URL로 리다이렉트.
 * <p>
 * 고객 환경 커스터마이즈:
 * - wbx.spring.sso.callback-url: 프론트엔드 콜백 (기본: /sso/callback)
 * - wbx.spring.sso.auto-register: SSO 최초 로그인 시 자동 사용자 등록
 */
@Slf4j
@Component
@RequiredArgsConstructor
@ConditionalOnProperty(name = "spring.security.oauth2.client.registration.azure.client-id")
public class SsoSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    private final WbxUserRepository userRepository;
    private final JwtProvider jwtProvider;
    private final WbxSpringProperties props;
    private final RefreshTokenService refreshTokenService;
    private final LoginHistoryRepository loginHistoryRepository;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                         Authentication authentication) throws IOException {
        OidcUser oidcUser = (OidcUser) authentication.getPrincipal();

        String email = oidcUser.getEmail();
        String name = oidcUser.getFullName();
        String oid = oidcUser.getAttribute("oid"); // Azure Object ID

        log.info("SSO login: email={}, name={}, oid={}", email, name, oid);

        // 사용자 조회 또는 자동 등록
        WbxUser user = userRepository.findByEmail(email)
                .orElseGet(() -> autoRegisterSsoUser(email, name, oid));

        // Azure OID 업데이트
        if (oid != null && !oid.equals(user.getAzureOid())) {
            user.setAzureOid(oid);
            user.setSsoProvider("azure");
        }
        user.recordLoginSuccess();
        userRepository.save(user);

        // JWT 발급
        String token = jwtProvider.generateToken(user.toUserDetails());
        String ip = request.getRemoteAddr();
        String refreshToken = refreshTokenService.create(user.getId(), "SSO", ip);

        // 로그인 이력
        loginHistoryRepository.save(WbxLoginHistory.builder()
                .userId(user.getId()).email(email)
                .action("LOGIN_SUCCESS").authMethod("SSO_AZURE")
                .ipAddress(ip)
                .build());

        // 프론트엔드 콜백 리다이렉트 (JWT를 query param으로 전달)
        String callbackUrl = String.format("/sso/callback?access_token=%s&refresh_token=%s",
                token, refreshToken);
        getRedirectStrategy().sendRedirect(request, response, callbackUrl);
    }

    private WbxUser autoRegisterSsoUser(String email, String fullName, String azureOid) {
        log.info("Auto-registering SSO user: {}", email);
        String username = email.split("@")[0];
        // username 중복 방지
        if (userRepository.existsByUsername(username)) {
            username = username + "_" + System.currentTimeMillis() % 10000;
        }

        WbxUser user = WbxUser.builder()
                .email(email)
                .username(username)
                .fullName(fullName != null ? fullName : username)
                .hashedPassword("") // SSO 사용자는 비밀번호 없음
                .isActive(true)
                .isAdmin(false)
                .ssoProvider("azure")
                .azureOid(azureOid)
                .build();
        return userRepository.save(user);
    }
}
