package com.unicorn.hgzero.meeting.infra.event.publisher;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.unicorn.hgzero.meeting.infra.event.dto.MeetingStartedEvent;
import com.unicorn.hgzero.meeting.infra.event.dto.MeetingEndedEvent;
import com.unicorn.hgzero.meeting.infra.event.dto.TodoAssignedEvent;
import com.unicorn.hgzero.meeting.infra.event.dto.NotificationRequestEvent;
import java.time.LocalDate;
import java.time.LocalDateTime;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;

/**
 * Event Hub 이벤트 발행 구현체
 * Kafka를 통한 이벤트 발행
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class EventHubPublisher implements EventPublisher {

    private final KafkaTemplate<String, String> kafkaTemplate;
    private final ObjectMapper objectMapper;

    @Value("${app.event.topic.meeting-started:meeting-started}")
    private String meetingStartedTopic;

    @Value("${app.event.topic.meeting-ended:meeting-ended}")
    private String meetingEndedTopic;

    @Value("${app.event.topic.todo-assigned:todo-assigned}")
    private String todoAssignedTopic;

    @Value("${app.event.topic.notification-request:notification-request}")
    private String notificationRequestTopic;

    @Value("${app.event.topic.todo-completed:todo-completed}")
    private String todoCompletedTopic;

    @Value("${app.event.topic.minutes-finalized:minutes-finalized}")
    private String minutesFinalizedTopic;

    @Override
    public void publishMeetingStarted(MeetingStartedEvent event) {
        try {
            String payload = objectMapper.writeValueAsString(event);
            kafkaTemplate.send(meetingStartedTopic, event.getMeetingId(), payload);
            log.info("회의 시작 이벤트 발행 완료 - meetingId: {}", event.getMeetingId());
        } catch (Exception e) {
            log.error("회의 시작 이벤트 발행 실패 - meetingId: {}", event.getMeetingId(), e);
            throw new RuntimeException("회의 시작 이벤트 발행 실패", e);
        }
    }

    @Override
    public void publishMeetingEnded(MeetingEndedEvent event) {
        try {
            String payload = objectMapper.writeValueAsString(event);
            kafkaTemplate.send(meetingEndedTopic, event.getMeetingId(), payload);
            log.info("회의 종료 이벤트 발행 완료 - meetingId: {}", event.getMeetingId());
        } catch (Exception e) {
            log.error("회의 종료 이벤트 발행 실패 - meetingId: {}", event.getMeetingId(), e);
            throw new RuntimeException("회의 종료 이벤트 발행 실패", e);
        }
    }

    @Override
    public void publishTodoAssigned(TodoAssignedEvent event) {
        try {
            String payload = objectMapper.writeValueAsString(event);
            kafkaTemplate.send(todoAssignedTopic, event.getTodoId(), payload);
            log.info("Todo 할당 이벤트 발행 완료 - todoId: {}", event.getTodoId());
        } catch (Exception e) {
            log.error("Todo 할당 이벤트 발행 실패 - todoId: {}", event.getTodoId(), e);
            throw new RuntimeException("Todo 할당 이벤트 발행 실패", e);
        }
    }

    @Override
    public void publishNotificationRequest(NotificationRequestEvent event) {
        try {
            String payload = objectMapper.writeValueAsString(event);
            kafkaTemplate.send(notificationRequestTopic, event.getRecipientId(), payload);
            log.info("알림 요청 이벤트 발행 완료 - type: {}, recipientId: {}", 
                    event.getNotificationType(), event.getRecipientId());
        } catch (Exception e) {
            log.error("알림 요청 이벤트 발행 실패 - type: {}, recipientId: {}", 
                    event.getNotificationType(), event.getRecipientId(), e);
            throw new RuntimeException("알림 요청 이벤트 발행 실패", e);
        }
    }

    // 편의 메서드 구현

    @Override
    public void publishTodoAssigned(String todoId, String title, String assigneeId, String assigneeName, 
                                   String assignedBy, String assignedByName, LocalDate dueDate) {
        TodoAssignedEvent event = TodoAssignedEvent.builder()
                .todoId(todoId)
                .title(title)
                .assigneeId(assigneeId)
                .assigneeName(assigneeName)
                .assignedBy(assignedBy)
                .assignedByName(assignedByName)
                .dueDate(dueDate)
                .assignedAt(LocalDateTime.now())
                .build();
        
        publishTodoAssigned(event);
    }

    @Override
    public void publishTodoCompleted(String todoId, String title, String assigneeId, String assigneeName,
                                   String completedBy, String completedByName) {
        try {
            // Todo 완료 이벤트는 NotificationRequestEvent로 발행
            NotificationRequestEvent event = NotificationRequestEvent.builder()
                    .notificationType("TODO_COMPLETED")
                    .recipientId(assigneeId)
                    .recipientName(assigneeName)
                    .title("Todo 완료")
                    .message(String.format("Todo '%s'가 완료되었습니다", title))
                    .relatedEntityId(todoId)
                    .relatedEntityType("TODO")
                    .requestedBy(completedBy)
                    .requestedByName(completedByName)
                    .eventTime(LocalDateTime.now())
                    .build();

            String payload = objectMapper.writeValueAsString(event);
            kafkaTemplate.send(todoCompletedTopic, todoId, payload);
            log.info("Todo 완료 이벤트 발행 완료 - todoId: {}", todoId);
        } catch (Exception e) {
            log.error("Todo 완료 이벤트 발행 실패 - todoId: {}", todoId, e);
            throw new RuntimeException("Todo 완료 이벤트 발행 실패", e);
        }
    }

    @Override
    public void publishMinutesFinalized(String minutesId, String title, String finalizedBy, String finalizedByName) {
        try {
            // 회의록 확정 이벤트는 NotificationRequestEvent로 발행
            NotificationRequestEvent event = NotificationRequestEvent.builder()
                    .notificationType("MINUTES_FINALIZED")
                    .recipientId(finalizedBy)
                    .recipientName(finalizedByName)
                    .title("회의록 확정")
                    .message(String.format("회의록 '%s'가 확정되었습니다", title))
                    .relatedEntityId(minutesId)
                    .relatedEntityType("MINUTES")
                    .requestedBy(finalizedBy)
                    .requestedByName(finalizedByName)
                    .eventTime(LocalDateTime.now())
                    .build();

            String payload = objectMapper.writeValueAsString(event);
            kafkaTemplate.send(minutesFinalizedTopic, minutesId, payload);
            log.info("회의록 확정 이벤트 발행 완료 - minutesId: {}", minutesId);
        } catch (Exception e) {
            log.error("회의록 확정 이벤트 발행 실패 - minutesId: {}", minutesId, e);
            throw new RuntimeException("회의록 확정 이벤트 발행 실패", e);
        }
    }
}