package roomescape.schedule.business import ScheduleException import com.github.f4b6a3.tsid.TsidFactory import io.github.oshai.kotlinlogging.KLogger 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.member.business.MemberService import roomescape.schedule.exception.ScheduleErrorCode import roomescape.schedule.infrastructure.persistence.ScheduleEntity import roomescape.schedule.infrastructure.persistence.ScheduleRepository import roomescape.schedule.infrastructure.persistence.ScheduleStatus import roomescape.schedule.web.* import java.time.LocalDate private val log: KLogger = KotlinLogging.logger {} @Service class ScheduleService( private val scheduleRepository: ScheduleRepository, private val scheduleValidator: ScheduleValidator, private val tsidFactory: TsidFactory, private val memberService: MemberService ) { @Transactional(readOnly = true) fun findThemesByDate(date: LocalDate): AvailableThemeIdListResponse { log.info { "[ScheduleService.findThemesByDate] 동일한 날짜의 모든 테마 조회: date=$date" } return scheduleRepository.findAllByDate(date) .toThemeIdListResponse() .also { log.info { "[ScheduleService.findThemesByDate] date=${date} 인 ${it.themeIds.size}개 테마 조회 완료" } } } @Transactional(readOnly = true) fun findSchedules(date: LocalDate, themeId: Long): ScheduleRetrieveListResponse { log.info { "[ScheduleService.findSchedules] 동일한 날짜와 테마인 모든 일정 조회: date=${date}, themeId=${themeId}" } return scheduleRepository.findAllByDateAndThemeId(date, themeId) .toRetrieveListResponse() .also { log.info { "[ScheduleService.findSchedules] date=${date}, themeId=${themeId} 인 ${it.schedules.size}개 일정 조회 완료" } } } @Transactional(readOnly = true) fun findDetail(id: Long): ScheduleDetailRetrieveResponse { log.info { "[ScheduleService.findDetail] 일정 상세 정보조회 시작: id=$id" } val schedule: ScheduleEntity = findOrThrow(id) val createdBy = memberService.findById(schedule.createdBy).name val updatedBy = memberService.findById(schedule.updatedBy).name return schedule.toDetailRetrieveResponse(createdBy, updatedBy) .also { log.info { "[ScheduleService.findDetail] 일정 상세 조회 완료: id=$id" } } } @Transactional fun createSchedule(request: ScheduleCreateRequest): ScheduleCreateResponse { log.info { "[ScheduleService.createSchedule] 일정 생성 시작: date=${request.date}, time=${request.time}, themeId=${request.themeId}" } scheduleValidator.validateCanCreate(request) val schedule = ScheduleEntity( id = tsidFactory.next(), date = request.date, time = request.time, themeId = request.themeId, status = ScheduleStatus.AVAILABLE ) return ScheduleCreateResponse(scheduleRepository.save(schedule).id) .also { log.info { "[ScheduleService.createSchedule] 일정 생성 완료: id=${it.id}" } } } @Transactional fun updateSchedule(id: Long, request: ScheduleUpdateRequest) { log.info { "[ScheduleService.updateSchedule] 일정 수정 시작: id=$id, request=${request}" } if (request.isAllParamsNull()) { log.info { "[ScheduleService.updateSchedule] 일정 변경 사항 없음: id=$id" } return } val schedule: ScheduleEntity = findOrThrow(id) scheduleValidator.validateCanUpdate(schedule, request) schedule.modifyIfNotNull( request.time, request.status ).also { log.info { "[ScheduleService.updateSchedule] 일정 수정 완료: id=$id, request=${request}" } } } @Transactional fun deleteSchedule(id: Long) { log.info { "[ScheduleService.deleteSchedule] 일정 삭제 시작: id=$id" } val schedule: ScheduleEntity = findOrThrow(id) scheduleValidator.validateCanDelete(schedule) scheduleRepository.delete(schedule).also { log.info { "[ScheduleService.deleteSchedule] 일정 삭제 완료: id=$id" } } } private fun findOrThrow(id: Long): ScheduleEntity { log.info { "[ScheduleService.findOrThrow] 일정 조회 시작: id=$id" } return scheduleRepository.findByIdOrNull(id) ?.also { log.info { "[ScheduleService.findOrThrow] 일정 조회 완료: id=$id" } } ?: run { log.warn { "[ScheduleService.updateSchedule] 일정 조회 실패. id=$id" } throw ScheduleException(ScheduleErrorCode.SCHEDULE_NOT_FOUND) } } }