package com.kt.event.eventservice.presentation.controller;

import com.kt.event.common.dto.ApiResponse;
import com.kt.event.common.dto.PageResponse;
import com.kt.event.common.security.UserPrincipal;
import com.kt.event.eventservice.application.dto.request.*;
import com.kt.event.eventservice.application.dto.response.*;
import com.kt.event.eventservice.application.service.EventService;
import com.kt.event.eventservice.infrastructure.client.dto.AIRecommendationResponse;
import com.kt.event.eventservice.domain.enums.EventStatus;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

/**
 * 이벤트 컨트롤러
 *
 * 이벤트 전체 생명주기 관리 API를 제공합니다.
 *
 * @author Event Service Team
 * @version 1.0.0
 * @since 2025-10-23
 */
@Slf4j
@RestController
@RequestMapping("/events")
@RequiredArgsConstructor
@Tag(name = "Event", description = "이벤트 관리 API")
public class EventController {

    private final EventService eventService;

    /**
     * 이벤트 목적 선택 (Step 1: 이벤트 생성)
     *
     * @param request 목적 선택 요청
     * @param userPrincipal 인증된 사용자 정보
     * @return 생성된 이벤트 응답
     */
    @PostMapping("/objectives")
    @Operation(summary = "이벤트 목적 선택", description = "이벤트 생성의 첫 단계로 목적을 선택합니다.")
    public ResponseEntity<ApiResponse<EventCreatedResponse>> selectObjective(
            @Valid @RequestBody SelectObjectiveRequest request,
            @AuthenticationPrincipal UserPrincipal userPrincipal) {

        log.info("이벤트 목적 선택 API 호출 - userId: {}, objective: {}",
                 userPrincipal.getUserId(), request.getObjective());

        EventCreatedResponse response = eventService.createEvent(
            userPrincipal.getUserId(),
            userPrincipal.getStoreId(),
            request
        );

        return ResponseEntity.status(HttpStatus.CREATED)
            .body(ApiResponse.success(response));
    }

    /**
     * 이벤트 목록 조회
     *
     * @param status 상태 필터
     * @param search 검색어
     * @param objective 목적 필터
     * @param page 페이지 번호
     * @param size 페이지 크기
     * @param sort 정렬 기준
     * @param order 정렬 순서
     * @param userPrincipal 인증된 사용자 정보
     * @return 이벤트 목록 응답
     */
    @GetMapping
    @Operation(summary = "이벤트 목록 조회", description = "사용자의 이벤트 목록을 조회합니다.")
    public ResponseEntity<ApiResponse<PageResponse<EventDetailResponse>>> getEvents(
            @RequestParam(required = false) EventStatus status,
            @RequestParam(required = false) String search,
            @RequestParam(required = false) String objective,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size,
            @RequestParam(defaultValue = "createdAt") String sort,
            @RequestParam(defaultValue = "desc") String order,
            @AuthenticationPrincipal UserPrincipal userPrincipal) {

        log.info("이벤트 목록 조회 API 호출 - userId: {}", userPrincipal.getUserId());

        // Pageable 생성
        Sort.Direction direction = "asc".equalsIgnoreCase(order) ? Sort.Direction.ASC : Sort.Direction.DESC;
        Pageable pageable = PageRequest.of(page, size, Sort.by(direction, sort));

        Page<EventDetailResponse> events = eventService.getEvents(
            userPrincipal.getUserId(),
            status,
            search,
            objective,
            pageable
        );

        PageResponse<EventDetailResponse> pageResponse = PageResponse.<EventDetailResponse>builder()
            .content(events.getContent())
            .page(events.getNumber())
            .size(events.getSize())
            .totalElements(events.getTotalElements())
            .totalPages(events.getTotalPages())
            .first(events.isFirst())
            .last(events.isLast())
            .build();

        return ResponseEntity.ok(ApiResponse.success(pageResponse));
    }

    /**
     * 이벤트 상세 조회
     *
     * @param eventId 이벤트 ID
     * @param userPrincipal 인증된 사용자 정보
     * @return 이벤트 상세 응답
     */
    @GetMapping("/{eventId}")
    @Operation(summary = "이벤트 상세 조회", description = "특정 이벤트의 상세 정보를 조회합니다.")
    public ResponseEntity<ApiResponse<EventDetailResponse>> getEvent(
            @PathVariable String eventId,
            @AuthenticationPrincipal UserPrincipal userPrincipal) {

        log.info("이벤트 상세 조회 API 호출 - userId: {}, eventId: {}",
                 userPrincipal.getUserId(), eventId);

        EventDetailResponse response = eventService.getEvent(userPrincipal.getUserId(), eventId);

        return ResponseEntity.ok(ApiResponse.success(response));
    }

    /**
     * 이벤트 삭제
     *
     * @param eventId 이벤트 ID
     * @param userPrincipal 인증된 사용자 정보
     * @return 성공 응답
     */
    @DeleteMapping("/{eventId}")
    @Operation(summary = "이벤트 삭제", description = "이벤트를 삭제합니다. DRAFT 상태만 삭제 가능합니다.")
    public ResponseEntity<ApiResponse<Void>> deleteEvent(
            @PathVariable String eventId,
            @AuthenticationPrincipal UserPrincipal userPrincipal) {

        log.info("이벤트 삭제 API 호출 - userId: {}, eventId: {}",
                 userPrincipal.getUserId(), eventId);

        eventService.deleteEvent(userPrincipal.getUserId(), eventId);

        return ResponseEntity.ok(ApiResponse.success(null));
    }

    /**
     * 이벤트 배포
     *
     * @param eventId 이벤트 ID
     * @param userPrincipal 인증된 사용자 정보
     * @return 성공 응답
     */
    @PostMapping("/{eventId}/publish")
    @Operation(summary = "이벤트 배포", description = "이벤트를 배포합니다. DRAFT → PUBLISHED 상태 변경.")
    public ResponseEntity<ApiResponse<Void>> publishEvent(
            @PathVariable String eventId,
            @AuthenticationPrincipal UserPrincipal userPrincipal) {

        log.info("이벤트 배포 API 호출 - userId: {}, eventId: {}",
                 userPrincipal.getUserId(), eventId);

        eventService.publishEvent(userPrincipal.getUserId(), eventId);

        return ResponseEntity.ok(ApiResponse.success(null));
    }

    /**
     * 이벤트 종료
     *
     * @param eventId 이벤트 ID
     * @param userPrincipal 인증된 사용자 정보
     * @return 성공 응답
     */
    @PostMapping("/{eventId}/end")
    @Operation(summary = "이벤트 종료", description = "이벤트를 종료합니다. PUBLISHED → ENDED 상태 변경.")
    public ResponseEntity<ApiResponse<Void>> endEvent(
            @PathVariable String eventId,
            @AuthenticationPrincipal UserPrincipal userPrincipal) {

        log.info("이벤트 종료 API 호출 - userId: {}, eventId: {}",
                 userPrincipal.getUserId(), eventId);

        eventService.endEvent(userPrincipal.getUserId(), eventId);

        return ResponseEntity.ok(ApiResponse.success(null));
    }

    /**
     * 이미지 생성 요청
     *
     * @param eventId 이벤트 ID
     * @param request 이미지 생성 요청
     * @param userPrincipal 인증된 사용자 정보
     * @return 이미지 생성 응답 (Job ID 포함)
     */
    @PostMapping("/{eventId}/images")
    @Operation(summary = "이미지 생성 요청", description = "AI를 통해 이벤트 이미지를 생성합니다.")
    public ResponseEntity<ApiResponse<ImageGenerationResponse>> requestImageGeneration(
            @PathVariable String eventId,
            @Valid @RequestBody ImageGenerationRequest request,
            @AuthenticationPrincipal UserPrincipal userPrincipal) {

        log.info("이미지 생성 요청 API 호출 - userId: {}, eventId: {}",
                 userPrincipal.getUserId(), eventId);

        ImageGenerationResponse response = eventService.requestImageGeneration(
            userPrincipal.getUserId(),
            eventId,
            request
        );

        return ResponseEntity.status(HttpStatus.ACCEPTED)
            .body(ApiResponse.success(response));
    }

    /**
     * 이미지 선택
     *
     * @param eventId 이벤트 ID
     * @param imageId 이미지 ID
     * @param request 이미지 선택 요청
     * @param userPrincipal 인증된 사용자 정보
     * @return 성공 응답
     */
    @PutMapping("/{eventId}/images/{imageId}/select")
    @Operation(summary = "이미지 선택", description = "생성된 이미지 중 하나를 선택합니다.")
    public ResponseEntity<ApiResponse<Void>> selectImage(
            @PathVariable String eventId,
            @PathVariable String imageId,
            @Valid @RequestBody SelectImageRequest request,
            @AuthenticationPrincipal UserPrincipal userPrincipal) {

        log.info("이미지 선택 API 호출 - userId: {}, eventId: {}, imageId: {}",
                 userPrincipal.getUserId(), eventId, imageId);

        eventService.selectImage(
            userPrincipal.getUserId(),
            eventId,
            imageId,
            request
        );

        return ResponseEntity.ok(ApiResponse.success(null));
    }

    /**
     * AI 추천 요청 (Step 2)
     *
     * @param eventId 이벤트 ID
     * @param request AI 추천 요청
     * @param userPrincipal 인증된 사용자 정보
     * @return AI 추천 요청 응답 (Job ID 포함)
     */
    @PostMapping("/{eventId}/ai-recommendations")
    @Operation(summary = "AI 추천 요청", description = "AI 서비스에 이벤트 추천 생성을 요청합니다.")
    public ResponseEntity<ApiResponse<JobAcceptedResponse>> requestAiRecommendations(
            @PathVariable String eventId,
            @Valid @RequestBody AiRecommendationRequest request,
            @AuthenticationPrincipal UserPrincipal userPrincipal) {

        log.info("AI 추천 요청 API 호출 - userId: {}, eventId: {}",
                 userPrincipal.getUserId(), eventId);

        JobAcceptedResponse response = eventService.requestAiRecommendations(
            userPrincipal.getUserId(),
            eventId,
            request
        );

        return ResponseEntity.status(HttpStatus.ACCEPTED)
            .body(ApiResponse.success(response));
    }

    /**
     * AI 추천안 조회 (Step 2-1)
     *
     * @param eventId 이벤트 ID
     * @param userPrincipal 인증된 사용자 정보
     * @return AI 추천 결과
     */
    @GetMapping("/{eventId}/ai-recommendations")
    @Operation(summary = "AI 추천안 조회", description = "AI Service에서 생성된 추천안을 조회합니다.")
    public ResponseEntity<ApiResponse<AIRecommendationResponse>> getAiRecommendations(
            @PathVariable String eventId,
            @AuthenticationPrincipal UserPrincipal userPrincipal) {

        log.info("AI 추천안 조회 API 호출 - userId: {}, eventId: {}",
                 userPrincipal.getUserId(), eventId);

        AIRecommendationResponse response = eventService.getAiRecommendations(
            userPrincipal.getUserId(),
            eventId
        );

        return ResponseEntity.ok(ApiResponse.success(response));
    }

    /**
     * AI 추천 선택 (Step 2-2)
     *
     * @param eventId 이벤트 ID
     * @param request AI 추천 선택 요청
     * @param userPrincipal 인증된 사용자 정보
     * @return 성공 응답
     */
    @PutMapping("/{eventId}/recommendations")
    @Operation(summary = "AI 추천 선택", description = "AI가 생성한 추천 중 하나를 선택하고 커스터마이징합니다.")
    public ResponseEntity<ApiResponse<Void>> selectRecommendation(
            @PathVariable String eventId,
            @Valid @RequestBody SelectRecommendationRequest request,
            @AuthenticationPrincipal UserPrincipal userPrincipal) {

        log.info("AI 추천 선택 API 호출 - userId: {}, eventId: {}, recommendationId: {}",
                 userPrincipal.getUserId(), eventId, request.getRecommendationId());

        eventService.selectRecommendation(
            userPrincipal.getUserId(),
            eventId,
            request
        );

        return ResponseEntity.ok(ApiResponse.success(null));
    }

    /**
     * 이미지 편집 (Step 3-3)
     *
     * @param eventId 이벤트 ID
     * @param imageId 이미지 ID
     * @param request 이미지 편집 요청
     * @param userPrincipal 인증된 사용자 정보
     * @return 이미지 편집 응답
     */
    @PutMapping("/{eventId}/images/{imageId}/edit")
    @Operation(summary = "이미지 편집", description = "선택된 이미지를 편집합니다.")
    public ResponseEntity<ApiResponse<ImageEditResponse>> editImage(
            @PathVariable String eventId,
            @PathVariable String imageId,
            @Valid @RequestBody ImageEditRequest request,
            @AuthenticationPrincipal UserPrincipal userPrincipal) {

        log.info("이미지 편집 API 호출 - userId: {}, eventId: {}, imageId: {}",
                 userPrincipal.getUserId(), eventId, imageId);

        ImageEditResponse response = eventService.editImage(
            userPrincipal.getUserId(),
            eventId,
            imageId,
            request
        );

        return ResponseEntity.ok(ApiResponse.success(response));
    }

    /**
     * 배포 채널 선택 (Step 4)
     *
     * @param eventId 이벤트 ID
     * @param request 배포 채널 선택 요청
     * @param userPrincipal 인증된 사용자 정보
     * @return 성공 응답
     */
    @PutMapping("/{eventId}/channels")
    @Operation(summary = "배포 채널 선택", description = "이벤트를 배포할 채널을 선택합니다.")
    public ResponseEntity<ApiResponse<Void>> selectChannels(
            @PathVariable String eventId,
            @Valid @RequestBody SelectChannelsRequest request,
            @AuthenticationPrincipal UserPrincipal userPrincipal) {

        log.info("배포 채널 선택 API 호출 - userId: {}, eventId: {}, channels: {}",
                 userPrincipal.getUserId(), eventId, request.getChannels());

        eventService.selectChannels(
            userPrincipal.getUserId(),
            eventId,
            request
        );

        return ResponseEntity.ok(ApiResponse.success(null));
    }

    /**
     * 이벤트 수정
     *
     * @param eventId 이벤트 ID
     * @param request 이벤트 수정 요청
     * @param userPrincipal 인증된 사용자 정보
     * @return 성공 응답
     */
    @PutMapping("/{eventId}")
    @Operation(summary = "이벤트 수정", description = "기존 이벤트의 정보를 수정합니다. DRAFT 상태만 수정 가능합니다.")
    public ResponseEntity<ApiResponse<EventDetailResponse>> updateEvent(
            @PathVariable String eventId,
            @Valid @RequestBody UpdateEventRequest request,
            @AuthenticationPrincipal UserPrincipal userPrincipal) {

        log.info("이벤트 수정 API 호출 - userId: {}, eventId: {}",
                 userPrincipal.getUserId(), eventId);

        EventDetailResponse response = eventService.updateEvent(
            userPrincipal.getUserId(),
            eventId,
            request
        );

        return ResponseEntity.ok(ApiResponse.success(response));
    }
}
