package com.kt.event.eventservice.infrastructure.kafka;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.kt.event.eventservice.application.dto.kafka.AIEventGenerationJobMessage;
import com.kt.event.eventservice.application.service.NotificationService;
import com.kt.event.eventservice.domain.entity.AiRecommendation;
import com.kt.event.eventservice.domain.entity.Event;
import com.kt.event.eventservice.domain.entity.Job;
import com.kt.event.eventservice.domain.repository.EventRepository;
import com.kt.event.eventservice.domain.repository.JobRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.support.Acknowledgment;
import org.springframework.kafka.support.KafkaHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * AI 이벤트 생성 작업 메시지 구독 Consumer
 *
 * ai-event-generation-job 토픽의 메시지를 구독하여 처리합니다.
 *
 * @author Event Service Team
 * @version 1.0.0
 * @since 2025-10-29
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class AIJobKafkaConsumer {

    private final ObjectMapper objectMapper;
    private final JobRepository jobRepository;
    private final EventRepository eventRepository;
    private final NotificationService notificationService;

    /**
     * AI 이벤트 생성 작업 메시지 수신 처리
     *
     * @param message AI 이벤트 생성 작업 메시지
     * @param partition 파티션 번호
     * @param offset 오프셋
     * @param acknowledgment 수동 커밋용 Acknowledgment
     */
    @KafkaListener(
        topics = "${app.kafka.topics.ai-event-generation-job}",
        groupId = "${spring.kafka.consumer.group-id}",
        containerFactory = "kafkaListenerContainerFactory"
    )
    public void consumeAIEventGenerationJob(
        @Payload String payload,
        @Header(KafkaHeaders.RECEIVED_PARTITION) int partition,
        @Header(KafkaHeaders.OFFSET) long offset,
        Acknowledgment acknowledgment
    ) {
        try {
            log.info("AI 이벤트 생성 작업 메시지 수신 - Partition: {}, Offset: {}", partition, offset);

            // JSON을 객체로 변환
            AIEventGenerationJobMessage message = objectMapper.readValue(
                payload,
                AIEventGenerationJobMessage.class
            );

            log.info("AI 작업 메시지 파싱 완료 - JobId: {}, UserId: {}, Status: {}",
                message.getJobId(), message.getUserId(), message.getStatus());

            // 메시지 처리 로직
            processAIEventGenerationJob(message);

            // 수동 커밋
            acknowledgment.acknowledge();
            log.info("AI 이벤트 생성 작업 메시지 처리 완료 - JobId: {}", message.getJobId());

        } catch (Exception e) {
            log.error("AI 이벤트 생성 작업 메시지 처리 중 오류 발생 - Partition: {}, Offset: {}, Error: {}",
                partition, offset, e.getMessage(), e);
            // 에러 발생 시에도 커밋 (재처리 방지, DLQ 사용 권장)
            acknowledgment.acknowledge();
        }
    }

    /**
     * AI 이벤트 생성 작업 처리
     *
     * @param message AI 이벤트 생성 작업 메시지
     */
    @Transactional
    protected void processAIEventGenerationJob(AIEventGenerationJobMessage message) {
        try {
            String jobId = message.getJobId();

            // Job 조회
            Job job = jobRepository.findById(jobId).orElse(null);
            if (job == null) {
                log.warn("Job을 찾을 수 없습니다 - JobId: {}", message.getJobId());
                return;
            }

            String eventId = job.getEventId();

            // Event 조회 (모든 케이스에서 사용)
            Event event = eventRepository.findById(eventId).orElse(null);

            switch (message.getStatus()) {
                case "COMPLETED":
                    log.info("AI 작업 완료 처리 - JobId: {}, UserId: {}",
                        message.getJobId(), message.getUserId());

                    // Job 상태 업데이트
                    if (message.getAiRecommendation() != null) {
                        // AI 추천 데이터를 JSON 문자열로 저장 (또는 별도 처리)
                        String recommendationData = objectMapper.writeValueAsString(message.getAiRecommendation());
                        job.complete(recommendationData);
                    } else {
                        job.complete("AI 추천 완료");
                    }
                    jobRepository.save(job);

                    // Event 조회 및 AI 추천 저장
                    if (event != null && message.getAiRecommendation() != null) {
                        var aiData = message.getAiRecommendation();

                        // AiRecommendation 엔티티 생성 및 Event에 추가
                        AiRecommendation aiRecommendation = AiRecommendation.builder()
                            .eventName(aiData.getEventTitle())
                            .description(aiData.getEventDescription())
                            .promotionType(aiData.getEventType())
                            .targetAudience(aiData.getTargetKeywords() != null ?
                                String.join(", ", aiData.getTargetKeywords()) : null)
                            .build();

                        event.addAiRecommendation(aiRecommendation);
                        eventRepository.save(event);

                        log.info("AI 추천 저장 완료 - EventId: {}, RecommendationTitle: {}",
                            eventId, aiData.getEventTitle());

                        // 사용자에게 알림 전송
                        String userId = event.getUserId();
                        notificationService.notifyJobCompleted(
                            userId,
                            jobId,
                            "AI_RECOMMENDATION",
                            "AI 추천이 완료되었습니다."
                        );
                    } else {
                        if (event == null) {
                            log.warn("Event를 찾을 수 없습니다 - EventId: {}", eventId);
                        }
                    }
                    break;

                case "FAILED":
                    log.error("AI 작업 실패 처리 - JobId: {}, Error: {}",
                        message.getJobId(), message.getErrorMessage());

                    // Job 상태 업데이트
                    job.fail(message.getErrorMessage());
                    jobRepository.save(job);

                    // 사용자에게 실패 알림 전송
                    if (event != null) {
                        String userId = event.getUserId();
                        notificationService.notifyJobFailed(
                            userId,
                            jobId,
                            "AI_RECOMMENDATION",
                            "AI 추천에 실패했습니다: " + message.getErrorMessage()
                        );
                    }
                    break;

                case "PROCESSING":
                    log.info("AI 작업 진행 중 - JobId: {}", message.getJobId());

                    // Job 상태 업데이트
                    job.start();
                    jobRepository.save(job);

                    // 사용자에게 진행 상태 알림 전송
                    if (event != null) {
                        String userId = event.getUserId();
                        notificationService.notifyJobProgress(
                            userId,
                            jobId,
                            "AI_RECOMMENDATION",
                            job.getProgress()
                        );
                    }
                    break;

                default:
                    log.warn("알 수 없는 작업 상태 - JobId: {}, Status: {}",
                        message.getJobId(), message.getStatus());
            }

        } catch (Exception e) {
            log.error("AI 작업 처리 중 예외 발생 - JobId: {}, Error: {}",
                message.getJobId(), e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }
}
