// // 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 @Published var rouletteList = [GetNewRouletteResponse]() @Published var totalPercentage = Float(0) func addOption() { if (options.count >= 10) { return } options.append(RouletteOption(title: "", percentage: "")) calculateTotalPercentage() } func deleteOption(index: Int) { options.remove(at: index) calculateTotalPercentage() } func getAllRoulette(creatorId: Int) { self.isLoading = true repository.getAllRoulette(creatorId: creatorId) .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(ApiResponse<[GetNewRouletteResponse]>.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(id: 0, can: self.can, items: items) isLoading = false isShowPreview = true } func createOrUpdateRoulette(onSuccess: @escaping (Bool, String) -> Void) { if !isLoading { isLoading = true if validationOptions() { if rouletteId > 0 { updateRoulette(onSuccess: onSuccess) } else { createRoulette(onSuccess: onSuccess) } } } } private func validationOptions() -> Bool { var totalPercentage = Float(0) for option in options { if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { isLoading = false errorMessage = "옵션은 빈칸일 수 없습니다." isShowErrorPopup = true return false } if let percentage = Float(option.percentage) { totalPercentage += percentage } } if totalPercentage != Float(100) { isLoading = false errorMessage = "확률이 100%가 아닙니다" isShowErrorPopup = true return false } return true } private func createRoulette(onSuccess: @escaping (Bool, String) -> Void) { var items = [RouletteItem]() for option in options { if let percentage = Float(option.percentage) { items.append(RouletteItem(title: option.title, percentage: percentage)) } } 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 = 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, successMessage) } else { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowErrorPopup = true } } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowErrorPopup = true } } .store(in: &subscription) } private func updateRoulette(onSuccess: @escaping (Bool, String) -> Void) { var items = [RouletteItem]() for option in options { if let percentage = Float(option.percentage) { items.append(RouletteItem(title: option.title, percentage: percentage)) } } 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 { onSuccess(isActive, successMessage) } 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, percentage: String($0.percentage)) } self.options.removeAll() self.options.append(contentsOf: options) } else { self.canText = "" self.isActive = false self.rouletteId = 0 options.removeAll() self.addOption() self.addOption() } } calculateTotalPercentage() } func calculateTotalPercentage() { let totalPercent = options.map { let percentage = Float($0.percentage) if let percentage = percentage { return percentage } else { return Float(0) } }.reduce(0, +) self.totalPercentage = totalPercent } }