package com.kt.event.eventservice.application.service;

import com.kt.event.common.exception.BusinessException;
import com.kt.event.common.exception.ErrorCode;
import com.kt.event.eventservice.application.dto.request.SelectObjectiveRequest;
import com.kt.event.eventservice.application.dto.response.EventCreatedResponse;
import com.kt.event.eventservice.application.dto.response.EventDetailResponse;
import com.kt.event.eventservice.domain.entity.*;
import com.kt.event.eventservice.domain.enums.EventStatus;
import com.kt.event.eventservice.domain.repository.EventRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.Hibernate;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 이벤트 서비스
 *
 * 이벤트 전체 생명주기를 관리합니다.
 *
 * @author Event Service Team
 * @version 1.0.0
 * @since 2025-10-23
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class EventService {

    private final EventRepository eventRepository;

    /**
     * 이벤트 생성 (Step 1: 목적 선택)
     *
     * @param userId 사용자 ID (UUID)
     * @param storeId 매장 ID (UUID)
     * @param request 목적 선택 요청
     * @return 생성된 이벤트 응답
     */
    @Transactional
    public EventCreatedResponse createEvent(UUID userId, UUID storeId, SelectObjectiveRequest request) {
        log.info("이벤트 생성 시작 - userId: {}, storeId: {}, objective: {}",
                 userId, storeId, request.getObjective());

        // 이벤트 엔티티 생성
        Event event = Event.builder()
            .userId(userId)
            .storeId(storeId)
            .objective(request.getObjective())
            .eventName("") // 초기에는 비어있음, AI 추천 후 설정
            .status(EventStatus.DRAFT)
            .build();

        // 저장
        event = eventRepository.save(event);

        log.info("이벤트 생성 완료 - eventId: {}", event.getEventId());

        return EventCreatedResponse.builder()
            .eventId(event.getEventId())
            .status(event.getStatus())
            .objective(event.getObjective())
            .createdAt(event.getCreatedAt())
            .build();
    }

    /**
     * 이벤트 상세 조회
     *
     * @param userId 사용자 ID (UUID)
     * @param eventId 이벤트 ID
     * @return 이벤트 상세 응답
     */
    public EventDetailResponse getEvent(UUID userId, UUID eventId) {
        log.info("이벤트 조회 - userId: {}, eventId: {}", userId, eventId);

        Event event = eventRepository.findByEventIdAndUserId(eventId, userId)
            .orElseThrow(() -> new BusinessException(ErrorCode.EVENT_001));

        // Lazy 컬렉션 초기화
        Hibernate.initialize(event.getChannels());
        Hibernate.initialize(event.getGeneratedImages());
        Hibernate.initialize(event.getAiRecommendations());

        return mapToDetailResponse(event);
    }

    /**
     * 이벤트 목록 조회 (페이징, 필터링)
     *
     * @param userId 사용자 ID (UUID)
     * @param status 상태 필터
     * @param search 검색어
     * @param objective 목적 필터
     * @param pageable 페이징 정보
     * @return 이벤트 목록
     */
    public Page<EventDetailResponse> getEvents(
            UUID userId,
            EventStatus status,
            String search,
            String objective,
            Pageable pageable) {

        log.info("이벤트 목록 조회 - userId: {}, status: {}, search: {}, objective: {}",
                 userId, status, search, objective);

        Page<Event> events = eventRepository.findEventsByUser(userId, status, search, objective, pageable);

        return events.map(event -> {
            // Lazy 컬렉션 초기화
            Hibernate.initialize(event.getChannels());
            Hibernate.initialize(event.getGeneratedImages());
            Hibernate.initialize(event.getAiRecommendations());
            return mapToDetailResponse(event);
        });
    }

    /**
     * 이벤트 삭제
     *
     * @param userId 사용자 ID (UUID)
     * @param eventId 이벤트 ID
     */
    @Transactional
    public void deleteEvent(UUID userId, UUID eventId) {
        log.info("이벤트 삭제 - userId: {}, eventId: {}", userId, eventId);

        Event event = eventRepository.findByEventIdAndUserId(eventId, userId)
            .orElseThrow(() -> new BusinessException(ErrorCode.EVENT_001));

        if (!event.isDeletable()) {
            throw new BusinessException(ErrorCode.EVENT_002);
        }

        eventRepository.delete(event);

        log.info("이벤트 삭제 완료 - eventId: {}", eventId);
    }

    /**
     * 이벤트 배포
     *
     * @param userId 사용자 ID (UUID)
     * @param eventId 이벤트 ID
     */
    @Transactional
    public void publishEvent(UUID userId, UUID eventId) {
        log.info("이벤트 배포 - userId: {}, eventId: {}", userId, eventId);

        Event event = eventRepository.findByEventIdAndUserId(eventId, userId)
            .orElseThrow(() -> new BusinessException(ErrorCode.EVENT_001));

        // 배포 가능 여부 검증 및 상태 변경
        event.publish();

        eventRepository.save(event);

        log.info("이벤트 배포 완료 - eventId: {}", eventId);
    }

    /**
     * 이벤트 종료
     *
     * @param userId 사용자 ID (UUID)
     * @param eventId 이벤트 ID
     */
    @Transactional
    public void endEvent(UUID userId, UUID eventId) {
        log.info("이벤트 종료 - userId: {}, eventId: {}", userId, eventId);

        Event event = eventRepository.findByEventIdAndUserId(eventId, userId)
            .orElseThrow(() -> new BusinessException(ErrorCode.EVENT_001));

        event.end();

        eventRepository.save(event);

        log.info("이벤트 종료 완료 - eventId: {}", eventId);
    }

    // ==== Private Helper Methods ==== //

    /**
     * Event Entity를 EventDetailResponse DTO로 변환
     */
    private EventDetailResponse mapToDetailResponse(Event event) {
        return EventDetailResponse.builder()
            .eventId(event.getEventId())
            .userId(event.getUserId())
            .storeId(event.getStoreId())
            .eventName(event.getEventName())
            .description(event.getDescription())
            .objective(event.getObjective())
            .startDate(event.getStartDate())
            .endDate(event.getEndDate())
            .status(event.getStatus())
            .selectedImageId(event.getSelectedImageId())
            .selectedImageUrl(event.getSelectedImageUrl())
            .generatedImages(
                event.getGeneratedImages().stream()
                    .map(img -> EventDetailResponse.GeneratedImageDto.builder()
                        .imageId(img.getImageId())
                        .imageUrl(img.getImageUrl())
                        .style(img.getStyle())
                        .platform(img.getPlatform())
                        .isSelected(img.isSelected())
                        .createdAt(img.getCreatedAt())
                        .build())
                    .collect(Collectors.toList())
            )
            .aiRecommendations(
                event.getAiRecommendations().stream()
                    .map(rec -> EventDetailResponse.AiRecommendationDto.builder()
                        .recommendationId(rec.getRecommendationId())
                        .eventName(rec.getEventName())
                        .description(rec.getDescription())
                        .promotionType(rec.getPromotionType())
                        .targetAudience(rec.getTargetAudience())
                        .isSelected(rec.isSelected())
                        .build())
                    .collect(Collectors.toList())
            )
            .channels(event.getChannels())
            .createdAt(event.getCreatedAt())
            .updatedAt(event.getUpdatedAt())
            .build();
    }
}
