import Foundation
import Capacitor
import IonicLiveUpdates

/**
 * Please read the Capacitor iOS Plugin Development Guide
 * here: https://capacitorjs.com/docs/plugins/ios
 */
@objc(CAPLiveUpdatesPlugin)
class LiveUpdatesPlugin: CAPPlugin, CAPBridgedPlugin {
    let identifier = "CAPLiveUpdatesPlugin"
    let jsName = "LiveUpdates"
    let pluginMethods: [CAPPluginMethod] = [
        .init(name: "sync", returnType: CAPPluginReturnCallback),
        .init(name: "reload", returnType: CAPPluginReturnPromise),
        .init(name: "getConfig", returnType: CAPPluginReturnPromise),
        .init(name: "setConfig", returnType: CAPPluginReturnPromise),
        .init(name: "resetConfig", returnType: CAPPluginReturnPromise)
    ]

    private lazy var implementation = LiveUpdates(
        getConfig().getConfigJSON(),
        binaryIsNew: binaryIsNew,
        bundledAppUrl: Bundle.main.bundleURL.appendingPathComponent("public")
    )

    private var binaryIsNew: Bool {
        guard let vc = bridge?.viewController as? CAPBridgeViewController else { return false }
        return vc.isNewBinary
    }

    override func load() {
        guard implementation.enabled, let bridge = bridge else { return }
        implementation.setServerBasePath(for: bridge)
    }

    @objc func sync(_ call: CAPPluginCall) {
        guard implementation.enabled else {
            return call.resolve([
                "appId": implementation.liveUpdate.appId,
                "failStep": "CHECK",
                "message": "LiveUpdates has been disabled."
            ])
        }

        call.keepAlive = true

        Task.detached(priority: .userInitiated) {
            defer { self.bridge?.releaseCall(call) }

            do {
                let result = try await self.implementation.sync { progress in
                    call.resolve(["progress": progress])
                }
                call.resolve(with: result)
            } catch let error as LiveUpdateManager.SyncError {
                call.resolve(with: error)
            }
        }
    }

    @objc func getConfig(_ call: CAPPluginCall) {
        call.resolve(with: implementation.config)
    }

    @objc func setConfig(_ call: CAPPluginCall) {
        guard let options = try? call.decode(LiveUpdateConfiguration.Options.self) else {
            return call.reject("Invalid configuration")
        }

        do {
            try implementation.update(options)
        } catch {
            return call.reject("Failed updating configuration", nil, error)
        }

        call.resolve()
    }

    @objc func resetConfig(_ call: CAPPluginCall) {
        implementation.resetConfig()
        call.resolve()
    }

    @objc func reload(_ call: CAPPluginCall) {
        if implementation.disabled { return call.resolve() }
        guard let bridge = bridge else { return }
        implementation.setServerBasePath(for: bridge)
        DispatchQueue.main.async { [weak webView] in webView?.reload() }
        call.resolve()
    }
}
