package com.unicorn.hgzero.notification.controller;

import com.unicorn.hgzero.notification.domain.Notification;
import com.unicorn.hgzero.notification.dto.response.NotificationListResponse;
import com.unicorn.hgzero.notification.dto.response.NotificationResponse;
import com.unicorn.hgzero.notification.repository.NotificationRepository;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 알림 조회 API Controller
 *
 * 알림 이력 조회 API 제공
 * 알림 목록 조회, 특정 알림 상세 조회 지원
 *
 * @author 준호 (Backend Developer)
 * @version 1.0
 * @since 2025-10-23
 */
@Slf4j
@RestController
@RequestMapping("/notifications")
@RequiredArgsConstructor
@Tag(name = "Notification", description = "알림 조회 API")
public class NotificationController {

    private final NotificationRepository notificationRepository;

    /**
     * 알림 목록 조회
     *
     * @param referenceType 참조 유형 (MEETING, TODO) - optional
     * @param notificationType 알림 유형 (INVITATION, TODO_ASSIGNED 등) - optional
     * @param status 알림 상태 (PENDING, SENT, FAILED 등) - optional
     * @param startDate 시작 일시 - optional
     * @param endDate 종료 일시 - optional
     * @return 알림 목록
     */
    @Operation(summary = "알림 목록 조회", description = "다양한 조건으로 알림 목록을 조회합니다")
    @ApiResponses(value = {
        @ApiResponse(
            responseCode = "200",
            description = "조회 성공",
            content = @Content(schema = @Schema(implementation = NotificationListResponse.class))
        ),
        @ApiResponse(responseCode = "400", description = "잘못된 요청"),
        @ApiResponse(responseCode = "500", description = "서버 오류")
    })
    @GetMapping
    public ResponseEntity<List<NotificationListResponse>> getNotifications(
        @Parameter(description = "참조 유형 (MEETING, TODO)")
        @RequestParam(required = false) Notification.ReferenceType referenceType,

        @Parameter(description = "알림 유형 (INVITATION, TODO_ASSIGNED, TODO_REMINDER 등)")
        @RequestParam(required = false) Notification.NotificationType notificationType,

        @Parameter(description = "알림 상태 (PENDING, PROCESSING, SENT, FAILED, PARTIAL)")
        @RequestParam(required = false) Notification.NotificationStatus status,

        @Parameter(description = "시작 일시 (yyyy-MM-dd'T'HH:mm:ss)")
        @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startDate,

        @Parameter(description = "종료 일시 (yyyy-MM-dd'T'HH:mm:ss)")
        @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endDate
    ) {
        log.info("알림 목록 조회 - ReferenceType: {}, NotificationType: {}, Status: {}, StartDate: {}, EndDate: {}",
            referenceType, notificationType, status, startDate, endDate);

        List<Notification> notifications;

        // 조건별 조회
        if (notificationType != null) {
            notifications = notificationRepository.findByNotificationType(notificationType);
        } else if (status != null) {
            notifications = notificationRepository.findByStatusIn(List.of(status));
        } else if (startDate != null && endDate != null) {
            notifications = notificationRepository.findByCreatedAtBetween(startDate, endDate);
        } else {
            // 기본: 모든 알림 조회 (최근 순)
            notifications = notificationRepository.findAll();
        }

        List<NotificationListResponse> response = notifications.stream()
            .map(NotificationListResponse::from)
            .collect(Collectors.toList());

        log.info("알림 목록 조회 완료 - 조회 건수: {}", response.size());
        return ResponseEntity.ok(response);
    }

    /**
     * 특정 알림 상세 조회
     *
     * @param notificationId 알림 ID
     * @return 알림 상세 정보 (수신자 목록 포함)
     */
    @Operation(summary = "알림 상세 조회", description = "특정 알림의 상세 정보를 조회합니다 (수신자 목록 포함)")
    @ApiResponses(value = {
        @ApiResponse(
            responseCode = "200",
            description = "조회 성공",
            content = @Content(schema = @Schema(implementation = NotificationResponse.class))
        ),
        @ApiResponse(responseCode = "404", description = "알림을 찾을 수 없음"),
        @ApiResponse(responseCode = "500", description = "서버 오류")
    })
    @GetMapping("/{notificationId}")
    public ResponseEntity<NotificationResponse> getNotification(
        @Parameter(description = "알림 ID", required = true)
        @PathVariable String notificationId
    ) {
        log.info("알림 상세 조회 - NotificationId: {}", notificationId);

        Notification notification = notificationRepository.findById(notificationId)
            .orElseThrow(() -> {
                log.error("알림을 찾을 수 없음 - NotificationId: {}", notificationId);
                return new RuntimeException("알림을 찾을 수 없습니다: " + notificationId);
            });

        NotificationResponse response = NotificationResponse.from(notification);

        log.info("알림 상세 조회 완료 - NotificationId: {}", notificationId);
        return ResponseEntity.ok(response);
    }

    /**
     * 알림 상태별 통계 조회 (모니터링용)
     *
     * @param startDate 시작 일시
     * @param endDate 종료 일시
     * @return 상태별 알림 건수
     */
    @Operation(summary = "알림 통계 조회", description = "기간별 알림 상태 통계를 조회합니다")
    @GetMapping("/statistics")
    public ResponseEntity<Object> getStatistics(
        @Parameter(description = "시작 일시")
        @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startDate,

        @Parameter(description = "종료 일시")
        @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endDate
    ) {
        log.info("알림 통계 조회 - StartDate: {}, EndDate: {}", startDate, endDate);

        long sentCount = notificationRepository.countByStatusAndCreatedAtBetween(
            Notification.NotificationStatus.SENT, startDate, endDate
        );

        long failedCount = notificationRepository.countByStatusAndCreatedAtBetween(
            Notification.NotificationStatus.FAILED, startDate, endDate
        );

        long partialCount = notificationRepository.countByStatusAndCreatedAtBetween(
            Notification.NotificationStatus.PARTIAL, startDate, endDate
        );

        var statistics = new Object() {
            public final long sent = sentCount;
            public final long failed = failedCount;
            public final long partial = partialCount;
            public final long total = sentCount + failedCount + partialCount;
        };

        log.info("알림 통계 조회 완료 - Sent: {}, Failed: {}, Partial: {}, Total: {}",
            sentCount, failedCount, partialCount, statistics.total);

        return ResponseEntity.ok(statistics);
    }
}
