package com.devjob.application.event;

import com.devjob.application.client.NotificationHttpClient;
import com.devjob.application.client.UserHttpClient;
import com.devjob.application.dto.EmailRequest;
import com.devjob.application.dto.MemberInfo;
import com.devjob.common.dto.ApiResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

/**
 * EP26: ApplicationAppliedEvent 리스너 — 지원 완료 이메일을 보낸다.
 *
 * - {@code @TransactionalEventListener(phase = AFTER_COMMIT)} : 지원 저장
 *   트랜잭션이 "성공적으로 커밋된 이후"에만 실행된다. 트랜잭션 도중
 *   롤백되면 이 리스너는 아예 호출되지 않는다.
 * - {@code @Async} : 별도 스레드에서 실행되어, 알림 발송이 느려지거나
 *   실패해도 지원 API의 응답 시간/성공 여부에 영향을 주지 않는다.
 *
 * EP27에서 NotificationHttpClient에 Circuit Breaker + Fallback을
 * 추가해 devjob-notification 장애 시에도 안전하게 동작하도록 만든다.
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ApplicationAppliedEventListener {

    private final UserHttpClient userHttpClient;
    private final NotificationHttpClient notificationHttpClient;

    @Async
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void onApplicationApplied(ApplicationAppliedEvent event) {
        try {
            ApiResponse<MemberInfo> userResponse = userHttpClient.getUser(event.userId());
            MemberInfo member = userResponse.data();
            if (member == null || member.email() == null) {
                log.warn("[Notification] 회원 정보를 찾을 수 없어 알림을 보내지 않습니다. userId={}", event.userId());
                return;
            }

            EmailRequest emailRequest = new EmailRequest(
                    event.userId(),
                    member.email(),
                    "[DevJob] 지원이 완료되었습니다",
                    "%s(%s) 공고에 지원이 완료되었습니다. (지원 ID: %d)"
                            .formatted(event.jobTitle(), event.companyName(), event.applicationId())
            );

            notificationHttpClient.sendEmail(emailRequest);
            log.info("[Notification] 지원 완료 메일 발송 요청 완료 - applicationId={}, email={}",
                    event.applicationId(), member.email());
        } catch (Exception e) {
            // 알림 발송 실패가 지원 자체의 성공 여부에 영향을 주지 않도록 여기서 흡수한다.
            log.error("[Notification] 지원 완료 메일 발송 실패 - applicationId={}", event.applicationId(), e);
        }
    }
}
