//
//  Patcher.swift
//  PadelClub
//
//  Created by Laurent Morvillier on 21/06/2024.
//

import Foundation
import LeStorage

enum ManualPatch: String {
    case disconnect
    
    var id: String {
        return "padelclub.app.manual.patch.\(self.rawValue)"
    }
}

class ManualPatcher {
    
    static func patchIfPossible(_ patch: ManualPatch) -> Bool {
        if UserDefaults.standard.value(forKey: patch.id) == nil {
            do {
                Logger.log(">>> Patches \(patch.rawValue)...")
                let result = try self._applyPatch(patch)
                UserDefaults.standard.setValue(true, forKey: patch.id)
                return result
            } catch {
                Logger.error(error)
            }
        }
        return false
    }
    
    fileprivate static func _applyPatch(_ patch: ManualPatch) throws -> Bool {
        switch patch {
        case .disconnect:
            let rawToken = try? StoreCenter.main.rawTokenShouldNotBeUsed()
            if StoreCenter.main.userName != nil || StoreCenter.main.userId != nil || rawToken != nil {
                DataStore.shared.disconnect()
                return true
            } else {
                return false
            }
        }
    }
}

enum PatchError: Error {
    case patchError(message: String)
}

enum Patch: String, CaseIterable {
    case cleanLogs
    case syncUpgrade
    case updateTournaments
    case cleanPurchaseApiCalls
    
    var id: String {
        return "padelclub.app.patch.\(self.rawValue)"
    }
}

class AutomaticPatcher {
    
    static func applyAllWhenApplicable() {
        for patch in Patch.allCases {
            self.patchIfPossible(patch)
        }
    }
    
    static func patchIfPossible(_ patch: Patch) {
        if UserDefaults.standard.value(forKey: patch.id) == nil {
            do {
                Logger.log(">>> Patches \(patch.rawValue)...")
                try self._applyPatch(patch)
                UserDefaults.standard.setValue(true, forKey: patch.id)
            } catch {
                Logger.error(error)
            }
        }
    }
    
    fileprivate static func _applyPatch(_ patch: Patch) throws {
        switch patch {
        case .cleanLogs: self._cleanLogs()
        case .syncUpgrade: self._syncUpgrade()
        case .updateTournaments: self._updateTournaments()
        case .cleanPurchaseApiCalls: self._cleanPurchaseApiCalls()
        }
    }
    
    fileprivate static func _cleanLogs() {
        StoreCenter.main.resetLoggingCollections()
    }
    
    fileprivate static func _syncUpgrade() {
        for tournament in DataStore.shared.tournaments {
            let id = tournament.id
            
            guard let store = TournamentLibrary.shared.store(tournamentId: tournament.id) else { continue }
            
            for round in store.rounds {
                round.storeId = id
            }
            store.rounds.addOrUpdate(contentOfs: store.rounds)
            for groupStage in store.groupStages {
                groupStage.storeId = id
            }
            store.groupStages.addOrUpdate(contentOfs: store.groupStages)
            for teamRegistration in store.teamRegistrations {
                teamRegistration.storeId = id
            }
            store.teamRegistrations.addOrUpdate(contentOfs: store.teamRegistrations)
            for pr in store.playerRegistrations {
                pr.storeId = id
            }
            store.playerRegistrations.addOrUpdate(contentOfs: store.playerRegistrations)
            for match in store.matches {
                match.storeId = id
            }
            store.matches.addOrUpdate(contentOfs: store.matches)
            for ts in store.teamScores {
                ts.storeId = id
            }
            store.teamScores.addOrUpdate(contentOfs: store.teamScores)
            for ms in store.matchSchedulers {
                ms.storeId = id
            }
            store.matchSchedulers.addOrUpdate(contentOfs: store.matchSchedulers)

        }
    }
    
    fileprivate static func _updateTournaments() {
        DataStore.shared.tournaments.addOrUpdate(contentOfs: DataStore.shared.tournaments)
    }
    
    fileprivate static func _cleanPurchaseApiCalls() {
        StoreCenter.main.resetApiCalls(type: Purchase.self)
    }
    
}
