import Sparkle
import Foundation
import OSLog

@MainActor
final class SparkleUpdater: NSObject, ObservableObject {
    private lazy var controller: SPUStandardUpdaterController = {
        SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: self, userDriverDelegate: nil)
    }()
    private let logger = Logger(subsystem: "net.24unix.iKeyMon", category: "Sparkle")
    private let verboseLogging: Bool

    override init() {
        self.verboseLogging = ProcessInfo.processInfo.environment["SPARKLE_VERBOSE_LOGGING"] == "1"
        super.init()
        _ = controller
        log("Sparkle updater initialized (verbose=\(verboseLogging)).")
    }

    var automaticallyChecksForUpdates: Bool {
        get { controller.updater.automaticallyChecksForUpdates }
        set { controller.updater.automaticallyChecksForUpdates = newValue }
    }

    var automaticallyDownloadsUpdates: Bool {
        get { controller.updater.automaticallyDownloadsUpdates }
        set { controller.updater.automaticallyDownloadsUpdates = newValue }
    }

    func checkForUpdates() {
        log("Manual check for updates triggered.")
        controller.checkForUpdates(nil)
    }

    private func log(_ message: String) {
        logger.log("\(message, privacy: .public)")
        if verboseLogging {
            print("[Sparkle] \(message)")
        }
    }

    private func logError(_ message: String) {
        logger.error("\(message, privacy: .public)")
        if verboseLogging {
            fputs("[Sparkle][error] \(message)\n", stderr)
        }
    }

    private func describe(update item: SUAppcastItem) -> String {
        let short = item.displayVersionString
        let build = item.versionString
        return "\(short) (build \(build))"
    }
}

@MainActor
extension SparkleUpdater: SPUUpdaterDelegate {
    func updater(_ updater: SPUUpdater, didFinishLoading appcast: SUAppcast) {
        log("Loaded Sparkle appcast containing \(appcast.items.count) item(s).")
    }

    func updater(_ updater: SPUUpdater, didFindValidUpdate item: SUAppcastItem) {
        log("Found valid update \(describe(update: item))")
    }

    func updaterDidNotFindUpdate(_ updater: SPUUpdater) {
        log("No updates available.")
    }

    func updater(_ updater: SPUUpdater, willDownloadUpdate item: SUAppcastItem, with request: NSMutableURLRequest) {
        log("Downloading \(describe(update: item)) from \(request.url?.absoluteString ?? "unknown URL")")
    }

    func updater(_ updater: SPUUpdater, didDownloadUpdate item: SUAppcastItem) {
        log("Finished downloading \(describe(update: item))")
    }

    func updater(_ updater: SPUUpdater, failedToDownloadUpdate item: SUAppcastItem, error: Error) {
        logError("Failed to download \(describe(update: item)): \(error.localizedDescription)")
    }

    func userDidCancelDownload(_ updater: SPUUpdater) {
        log("User cancelled Sparkle download.")
    }

    func updater(_ updater: SPUUpdater, willInstallUpdate item: SUAppcastItem) {
        log("Will install update \(describe(update: item))")
    }

    func updater(_ updater: SPUUpdater, didAbortWithError error: Error) {
        logError("Sparkle aborted: \(error.localizedDescription)")
    }
}
