//
//  RouletteSettingsViewModel.swift
//  SodaLive
//
//  Created by klaus on 2023/12/05.
//

import Foundation
import Combine

final class RouletteSettingsViewModel: ObservableObject {
    private let repository = RouletteRepository()
    private var subscription = Set<AnyCancellable>()
    
    @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
    
    var can = 0
    
    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 >= 6) {
            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..<options.count {
            options[i].percentage = Int(Double(options[i].weight) / Double(totalWeight) * 100)
        }
        
        removeAllAndAddOptions(options: options)
    }
    
    private func removeAllAndAddOptions(options: [RouletteOption]) {
        self.options.removeAll()
        self.options.append(contentsOf: options)
    }
    
    func getRoulette(creatorId: Int) {
        self.isLoading = true
        repository.getRoulette(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<GetRouletteResponse>.self, from: responseData)
                    
                    if let data = decoded.data, decoded.success {
                        self.isActive = data.isActive
                        
                        if data.can > 0 {
                            self.canText = String(data.can)
                        } else {
                            self.canText = ""
                        }
                        
                        if !data.items.isEmpty {
                            let options = data.items.map {
                                RouletteOption(title: $0.title, weight: $0.weight)
                            }
                            removeAllAndAddOptions(options: options)
                            recalculatePercentages()
                        } else {
                            self.addOption()
                            self.addOption()
                        }
                    } else {
                        self.isActive = false
                        self.canText = ""
                        self.addOption()
                        self.addOption()
                    }
                } 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
            
            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 = CreateOrUpdateRouletteRequest(can: can, isActive: isActive, items: items)
            repository.createOrUpdateRoulette(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)
        }
    }
}