import Foundation
import NucleicCore

/// Keeps the Mac awake while "Block sleep" is on in Settings ▸ General. Holds a process-activity
/// assertion with `.idleSystemSleepDisabled` — the same mechanism `caffeinate -i` uses — so the
/// system won't idle-sleep out from under long-running chats, builds, or agent work. It deliberately
/// leaves the *display* free to sleep (blocking that too would needlessly light up the screen) and,
/// unlike the container engine's assertion, keeps the system fully awake rather than
/// allowing-idle-sleep — that's the whole point of the switch.
///
/// A singleton so the one assertion is shared app-wide. The Settings toggle calls `setEnabled(_:)`
/// on change, and `applyStoredSetting()` re-applies the persisted choice at launch. Off by default
/// (opt-in): blocking sleep drains the battery, so nothing happens until the user asks for it.
@MainActor
final class SleepBlocker {
    static let shared = SleepBlocker()
    private init() {}

    /// `@AppStorage` key for the Settings switch. Off by default, so a plain `bool(forKey:)` (which
    /// reads an unset key as `false`) is exactly right here — no need for the `object(forKey:) as?
    /// Bool ?? true` opt-out dance used by on-by-default switches like the Dock bounce.
    static let enabledKey = "nucleic.power.blockSleep"
    static var isEnabled: Bool {
        UserDefaults.standard.bool(forKey: enabledKey)
    }

    /// The in-flight process-activity assertion while sleep is blocked, or nil when it isn't. Held
    /// so we can end it the moment the switch flips off.
    private var activity: NSObjectProtocol?

    /// Begin the assertion if `enabled` and one isn't already held; end it if not. Idempotent — safe
    /// to call after every toggle and at launch.
    func setEnabled(_ enabled: Bool) {
        if enabled, activity == nil {
            activity = ProcessInfo.processInfo.beginActivity(
                options: [.idleSystemSleepDisabled, .suddenTerminationDisabled],
                reason: "Block sleep is on in Nucleic Settings")
        } else if !enabled, let activity {
            ProcessInfo.processInfo.endActivity(activity)
            self.activity = nil
        }
    }

    /// Re-read the persisted switch and apply it. Called once at launch so a Mac that quit with the
    /// setting on comes back holding the assertion.
    func applyStoredSetting() {
        setEnabled(Self.isEnabled)
    }
}
