//
//  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<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
    
    @Published var selectedRoulette: SelectedRoulette? = nil
    
    var can = 0
    private var rouletteId = 0
    @Published var rouletteList = [GetNewRouletteResponse]()
    
    @Published var totalPercentage = Float(0)
    
    var availableActive: Bool = true
    
    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.1) || totalPercentage <= Float(99.99) {
            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 availableActive {
            if isActive {
                successMessage = "\(selectedRouletteTitle)로 설정하였습니다."
            } else {
                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 availableActive {
            if isActive {
                successMessage = "\(selectedRouletteTitle)을 활성화 했습니다."
            } else {
                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
    }
}