package roomescape.theme.business import com.github.f4b6a3.tsid.TsidFactory import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import roomescape.common.config.next import roomescape.theme.exception.ThemeErrorCode import roomescape.theme.exception.ThemeException import roomescape.theme.infrastructure.persistence.ThemeEntity import roomescape.theme.infrastructure.persistence.ThemeRepository import roomescape.theme.web.ThemeCreateRequest import roomescape.theme.web.ThemeRetrieveListResponse import roomescape.theme.web.ThemeRetrieveResponse import roomescape.theme.web.toResponse import java.time.LocalDate private val log = KotlinLogging.logger {} @Service class ThemeService( private val tsidFactory: TsidFactory, private val themeRepository: ThemeRepository, ) { @Transactional(readOnly = true) fun findById(id: Long): ThemeEntity { log.debug { "[ThemeService.findById] 테마 조회 시작: themeId=$id" } return themeRepository.findByIdOrNull(id) ?.also { log.info { "[ThemeService.findById] 테마 조회 완료: themeId=$id" } } ?: run { log.warn { "[ThemeService.findById] 테마 조회 실패: themeId=$id" } throw ThemeException(ThemeErrorCode.THEME_NOT_FOUND) } } @Transactional(readOnly = true) fun findThemes(): ThemeRetrieveListResponse { log.debug { "[ThemeService.findThemes] 모든 테마 조회 시작" } return themeRepository.findAll() .also { log.info { "[ThemeService.findThemes] ${it.size}개의 테마 조회 완료" } } .toResponse() } @Transactional(readOnly = true) fun findMostReservedThemes(count: Int): ThemeRetrieveListResponse { log.debug { "[ThemeService.findMostReservedThemes] 인기 테마 조회 시작: count=$count" } val today = LocalDate.now() val startDate = today.minusDays(7) val endDate = today.minusDays(1) return themeRepository.findPopularThemes(startDate, endDate, count) .also { log.info { "[ThemeService.findMostReservedThemes] ${it.size} 개의 인기 테마 조회 완료" } } .toResponse() } @Transactional fun createTheme(request: ThemeCreateRequest): ThemeRetrieveResponse { log.debug { "[ThemeService.createTheme] 테마 생성 시작: name=${request.name}" } if (themeRepository.existsByName(request.name)) { log.info { "[ThemeService.createTheme] 테마 생성 실패(이름 중복): name=${request.name}" } throw ThemeException(ThemeErrorCode.THEME_NAME_DUPLICATED) } val theme = ThemeEntity( _id = tsidFactory.next(), name = request.name, description = request.description, thumbnail = request.thumbnail ) return themeRepository.save(theme) .also { log.info { "[ThemeService.createTheme] 테마 생성 완료: themeId=${it.id}" } } .toResponse() } @Transactional fun deleteTheme(id: Long) { log.debug { "[ThemeService.deleteTheme] 테마 삭제 시작: themeId=$id" } if (themeRepository.isReservedTheme(id)) { log.info { "[ThemeService.deleteTheme] 테마 삭제 실패(예약이 있는 테마): themeId=$id" } throw ThemeException(ThemeErrorCode.THEME_ALREADY_RESERVED) } themeRepository.deleteById(id) .also { log.info { "[ThemeService.deleteTheme] 테마 삭제 완료: themeId=$id" } } } }