// // RouletteSettingsViewModel.swift // SodaLive // // Created by klaus on 2023/12/05. // import Foundation import Combine enum SelectedRoulette: Int { case ROULETTE_1 = 0 case ROULETTE_2 = 1 case ROULETTE_3 = 2 } final class RouletteSettingsViewModel: ObservableObject { private let repository = RouletteRepository() private var subscription = Set() @Published var isLoading = false @Published var errorMessage = "" @Published var isShowErrorPopup = false @Published var canText = "" { didSet { can = Int(canText) ?? 0 } } @Published var isActive = false @Published var options = [RouletteOption]() @Published var isShowPreview = false { didSet { if !isShowPreview { previewData = nil } } } @Published var previewData: RoulettePreview? = nil @Published var selectedRoulette: SelectedRoulette? = nil var can = 0 private var rouletteId = 0 private var rouletteList = [GetNewRouletteResponse]() func plusWeight(index: Int) { options[index].weight += 1 recalculatePercentages() } func subtractWeight(index: Int) { if options[index].weight > 1 { options[index].weight -= 1 recalculatePercentages() } } func addOption() { if (options.count >= 10) { return } options.append(RouletteOption(title: "", weight: 1)) recalculatePercentages() } func deleteOption(index: Int) { options.remove(at: index) recalculatePercentages() } private func recalculatePercentages() { let options = options var totalWeight = 0 for option in options { totalWeight += option.weight } guard totalWeight > 0 else { return } for i in 0...self, from: responseData) if let data = decoded.data, decoded.success { rouletteList.removeAll() rouletteList.append(contentsOf: data) selectRoulette(selectedRoulette: .ROULETTE_1) } else { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowErrorPopup = true } } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowErrorPopup = true } } .store(in: &subscription) } func onClickPreview() { isLoading = true var items = [RoulettePreviewItem]() for option in options { if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { isLoading = false errorMessage = "옵션은 빈칸일 수 없습니다." isShowErrorPopup = true return } items.append(RoulettePreviewItem(title: option.title, percent: "\(option.percentage)%")) } previewData = RoulettePreview(can: self.can, items: items) isLoading = false isShowPreview = true } func createOrUpdateRoulette(onSuccess: @escaping (Bool) -> Void) { if !isLoading { isLoading = true if rouletteId > 0 { updateRoulette(onSuccess: onSuccess) } else { createRoulette(onSuccess: onSuccess) } } } private func createRoulette(onSuccess: @escaping (Bool) -> Void) { var items = [RouletteItem]() for option in options { if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { isLoading = false errorMessage = "옵션은 빈칸일 수 없습니다." isShowErrorPopup = true return } items.append(RouletteItem(title: option.title, weight: option.weight)) } let request = CreateRouletteRequest(can: can, isActive: isActive, items: items) repository.createRoulette(request: request) .sink { result in switch result { case .finished: DEBUG_LOG("finish") case .failure(let error): ERROR_LOG(error.localizedDescription) } } receiveValue: { [unowned self] response in self.isLoading = false let responseData = response.data do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData) if decoded.success { onSuccess(isActive) } else { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowErrorPopup = true } } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowErrorPopup = true } } .store(in: &subscription) } private func updateRoulette(onSuccess: @escaping (Bool) -> Void) { var items = [RouletteItem]() for option in options { if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { isLoading = false errorMessage = "옵션은 빈칸일 수 없습니다." isShowErrorPopup = true return } items.append(RouletteItem(title: option.title, weight: option.weight)) } let selectedRoulette = rouletteList[selectedRoulette!.rawValue] if selectedRoulette.isActive == isActive && selectedRoulette.can == can && selectedRoulette.items == items { self.errorMessage = "변동사항이 없습니다." self.isShowErrorPopup = true self.isLoading = false return } let selectedRouletteTitle: String let successMessage: String switch (self.selectedRoulette) { case .ROULETTE_2: selectedRouletteTitle = "룰렛 2" case .ROULETTE_3: selectedRouletteTitle = "룰렛 3" default: selectedRouletteTitle = "룰렛 1" } if isActive { successMessage = "\(selectedRouletteTitle)을 활성화 했습니다." } else { successMessage = "\(selectedRouletteTitle)을 비활성화 했습니다." } let request = UpdateRouletteRequest(id: rouletteId, can: can, isActive: isActive, items: items) repository.updateRoulette(request: request) .sink { result in switch result { case .finished: DEBUG_LOG("finish") case .failure(let error): ERROR_LOG(error.localizedDescription) } } receiveValue: { [unowned self] response in self.isLoading = false let responseData = response.data do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData) if decoded.success { self.errorMessage = successMessage self.isShowErrorPopup = true onSuccess(isActive) } else { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowErrorPopup = true } } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowErrorPopup = true } } .store(in: &subscription) } func selectRoulette(selectedRoulette: SelectedRoulette) { if rouletteList.isEmpty && (selectedRoulette == .ROULETTE_2 || selectedRoulette == .ROULETTE_3) { errorMessage = "룰렛 1만 선택 가능" isShowErrorPopup = true return } if rouletteList.count == 1 && selectedRoulette == .ROULETTE_3 { errorMessage = "룰렛 1, 룰렛2만 선택 가능" isShowErrorPopup = true return } if self.selectedRoulette != selectedRoulette { self.selectedRoulette = selectedRoulette if rouletteList.count > selectedRoulette.rawValue { let roulette = rouletteList[selectedRoulette.rawValue] if roulette.can > 0 { self.canText = String(roulette.can) } else { self.canText = "" } self.rouletteId = roulette.id self.isActive = roulette.isActive let options = roulette.items.map { RouletteOption(title: $0.title, weight: $0.weight) } removeAllAndAddOptions(options: options) recalculatePercentages() } else { self.canText = "" self.isActive = false self.rouletteId = 0 options.removeAll() self.addOption() self.addOption() } } } }