SubscriptionController.java

package com.newbit.subscription.controller;

import java.util.List;

import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.newbit.auth.model.CustomUser;
import com.newbit.subscription.dto.request.SubscriptionRequest;
import com.newbit.subscription.dto.response.SubscriptionResponse;
import com.newbit.subscription.dto.response.SubscriptionStatusResponse;
import com.newbit.subscription.service.SubscriptionService;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
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.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Getter;

@RestController
@RequestMapping("/api/v1/subscriptions")
@RequiredArgsConstructor
@Tag(name = "시리즈 구독 API", description = "시리즈 구독 관련 API")
public class SubscriptionController {

    private final SubscriptionService subscriptionService;

    @PostMapping
    @PreAuthorize("isAuthenticated()")
    @Operation(
            summary = "시리즈 구독 토글",
            description = "시리즈 구독을 추가하거나 취소합니다. 이미 구독 중이면 취소, 구독 중이 아니면 구독 추가됩니다.",
            responses = {
                    @ApiResponse(
                            responseCode = "200", 
                            description = "구독 토글 성공",
                            content = @Content(
                                    mediaType = "application/json",
                                    schema = @Schema(implementation = SubscriptionResponse.class)
                            )
                    ),
                    @ApiResponse(responseCode = "400", description = "존재하지 않는 시리즈"),
                    @ApiResponse(responseCode = "401", description = "인증되지 않은 사용자")
            }
    )
    public ResponseEntity<SubscriptionResponse> toggleSubscription(
            @Parameter(description = "시리즈 구독 요청 정보", required = true)
            @Valid @RequestBody SubscriptionRequest request,
            @Parameter(description = "인증된 사용자 정보", required = true)
            @AuthenticationPrincipal CustomUser user
    ) {
        SubscriptionResponse response = subscriptionService.toggleSubscription(request.getSeriesId(), user.getUserId());
        return ResponseEntity.ok(response);
    }

    @GetMapping("/series/{seriesId}/status")
    @PreAuthorize("isAuthenticated()")
    @Operation(
            summary = "시리즈 구독 상태 확인",
            description = "로그인한 사용자가 특정 시리즈를 구독했는지 여부와 구독자 수를 확인합니다.",
            responses = {
                    @ApiResponse(
                            responseCode = "200", 
                            description = "구독 상태 확인 성공",
                            content = @Content(
                                    mediaType = "application/json",
                                    schema = @Schema(implementation = SubscriptionStatusResponse.class)
                            )
                    ),
                    @ApiResponse(responseCode = "400", description = "존재하지 않는 시리즈"),
                    @ApiResponse(responseCode = "401", description = "인증되지 않은 사용자")
            }
    )
    public ResponseEntity<SubscriptionStatusResponse> checkSubscriptionStatus(
            @Parameter(description = "시리즈 ID", required = true, example = "1")
            @PathVariable Long seriesId,
            @Parameter(description = "인증된 사용자 정보", required = true)
            @AuthenticationPrincipal CustomUser user
    ) {
        return ResponseEntity.ok(subscriptionService.getSubscriptionStatus(seriesId, user.getUserId()));
    }

    @GetMapping("/series/{seriesId}/count")
    @Operation(
            summary = "시리즈 구독자 수 조회",
            description = "특정 시리즈의 구독자 수를 조회합니다.",
            responses = {
                    @ApiResponse(
                            responseCode = "200", 
                            description = "구독자 수 조회 성공",
                            content = @Content(
                                    mediaType = "application/json",
                                    schema = @Schema(implementation = SubscriberCountResponse.class)
                            )
                    ),
                    @ApiResponse(responseCode = "400", description = "존재하지 않는 시리즈")
            }
    )
    public ResponseEntity<SubscriberCountResponse> getSubscriberCount(
            @Parameter(description = "시리즈 ID", required = true, example = "1")
            @PathVariable Long seriesId
    ) {
        int count = subscriptionService.getSubscriberCount(seriesId);
        return ResponseEntity.ok(new SubscriberCountResponse(seriesId, count));
    }
    
    @GetMapping("/user/list")
    @PreAuthorize("isAuthenticated()")
    @Operation(
            summary = "내 구독 목록 조회",
            description = "로그인한 사용자가 구독 중인 시리즈 목록을 조회합니다.",
            responses = {
                    @ApiResponse(
                            responseCode = "200", 
                            description = "구독 목록 조회 성공",
                            content = @Content(
                                    mediaType = "application/json",
                                    array = @ArraySchema(schema = @Schema(implementation = SubscriptionResponse.class))
                            )
                    ),
                    @ApiResponse(responseCode = "401", description = "인증되지 않은 사용자")
            }
    )
    public ResponseEntity<List<SubscriptionResponse>> getMySubscriptions(
            @Parameter(description = "인증된 사용자 정보", required = true)
            @AuthenticationPrincipal CustomUser user
    ) {
        return ResponseEntity.ok(subscriptionService.getUserSubscriptions(user.getUserId()));
    }
    
    @Getter
    @AllArgsConstructor
    @Schema(description = "구독자 수 응답")
    public static class SubscriberCountResponse {
        @Schema(description = "시리즈 ID", example = "1")
        private Long seriesId;
        
        @Schema(description = "구독자 수", example = "325")
        private int subscriberCount;
    }
}