SubscriptionService.java

package com.newbit.subscription.service;

import java.util.List;
import java.util.Optional;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.newbit.column.repository.SeriesRepository;
import com.newbit.subscription.dto.response.SubscriptionResponse;
import com.newbit.subscription.dto.response.SubscriptionStatusResponse;
import com.newbit.subscription.entity.Subscription;
import com.newbit.subscription.entity.SubscriptionId;
import com.newbit.subscription.repository.SubscriptionRepository;
import com.newbit.subscription.util.SubscriptionValidator;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@RequiredArgsConstructor
public class SubscriptionService {

    private final SubscriptionRepository subscriptionRepository;
    private final SeriesRepository seriesRepository;
    private final SubscriptionValidator validator;
    private final SubscriptionManager manager;

    @Transactional
    public SubscriptionResponse toggleSubscription(Long seriesId, Long userId) {
        try {
            validator.validateSeriesExists(seriesId, seriesRepository);
            
            SubscriptionId subscriptionId = new SubscriptionId(userId, seriesId);
            Optional<Subscription> existingSubscription = subscriptionRepository.findById(subscriptionId);
            
            if (existingSubscription.isPresent()) {
                return manager.cancelSubscription(existingSubscription.get());
            } else {
                return manager.createNewSubscription(userId, seriesId);
            }
        } catch (Exception e) {
            throw validator.handleSubscriptionError(e, "구독 토글 처리 중 오류 발생", seriesId, userId);
        }
    }
    
    @Transactional(readOnly = true)
    public SubscriptionStatusResponse getSubscriptionStatus(Long seriesId, Long userId) {
        try {
            validator.validateSeriesExists(seriesId, seriesRepository);
            
            boolean isSubscribed = subscriptionRepository.existsByUserIdAndSeriesId(userId, seriesId);
            int subscriberCount = subscriptionRepository.countBySeriesId(seriesId);
            
            return SubscriptionStatusResponse.of(seriesId, userId, isSubscribed, subscriberCount);
        } catch (Exception e) {
            throw validator.handleSubscriptionError(e, "구독 상태 조회 중 오류 발생", seriesId, userId);
        }
    }
    
    @Transactional(readOnly = true)
    public int getSubscriberCount(Long seriesId) {
        try {
            validator.validateSeriesExists(seriesId, seriesRepository);
            return subscriptionRepository.countBySeriesId(seriesId);
        } catch (Exception e) {
            throw validator.handleSubscriptionError(e, "구독자 수 조회 중 오류 발생", seriesId, null);
        }
    }
    
    @Transactional(readOnly = true)
    public List<SubscriptionResponse> getUserSubscriptions(Long userId) {
        try {
            return subscriptionRepository.findByUserId(userId).stream()
                    .map(SubscriptionResponse::from)
                    .toList();
        } catch (Exception e) {
            throw validator.handleSubscriptionError(e, "사용자 구독 목록 조회 중 오류 발생", null, userId);
        }
    }
    
    @Transactional(readOnly = true)
    public List<Long> getSeriesSubscribers(Long seriesId) {
        try {
            validator.validateSeriesExists(seriesId, seriesRepository);
            return subscriptionRepository.findBySeriesId(seriesId).stream()
                    .map(Subscription::getUserId)
                    .toList();
        } catch (Exception e) {
            throw validator.handleSubscriptionError(e, "시리즈 구독자 목록 조회 중 오류 발생", seriesId, null);
        }
    }
}