// The option lists every settings surface renders from — one source of truth shared by the
// touch/desktop SettingsView (Pickers), the tvOS pushed selection rows, and the gamepad settings
// screen (GamepadSettingsView's left/right cycling). Pure data + small pure helpers; anything that
// reads live view state (e.g. the bitrate slider mapping) stays on SettingsView.

#if os(macOS)
import AppKit
#endif
import PunktfunkKit
import SwiftUI

enum SettingsOptions {
    /// Compositor choices — the `tag` is the wire value (`PunktfunkConnection.Compositor` raw).
    static let compositors: [(label: String, tag: Int)] = [
        ("Automatic", 0),
        ("KWin (KDE Plasma)", 1),
        ("wlroots (Sway / Hyprland)", 2),
        ("Mutter (GNOME)", 3),
        ("gamescope", 4),
    ]

    static let audioChannels: [(label: String, tag: Int)] = [
        ("Stereo", 2),
        ("5.1 Surround", 6),
        ("7.1 Surround", 8),
    ]

    /// Virtual-pad types — the `tag` is the wire value (`PunktfunkConnection.GamepadType` raw).
    static let padTypes: [(label: String, tag: Int)] = [
        ("Automatic", 0),
        ("Xbox 360", 1),
        ("Xbox One", 3),
        ("DualSense", 2),
        ("DualShock 4", 4),
    ]

    static let hudPlacements: [(label: String, tag: String)] =
        HUDPlacement.allCases.map { ($0.label, $0.rawValue) }

    /// Video-codec preference (`DefaultsKey.codec`) — a soft preference the host falls back from.
    /// No AV1: this client's VideoToolbox path decodes H.264/HEVC only (hosts don't emit AV1 on
    /// the native path yet).
    static let codecs: [(label: String, tag: String)] = [
        ("Automatic", "auto"),
        ("HEVC (H.265)", "hevc"),
        ("H.264 (AVC)", "h264"),
    ]

    // MARK: - Bitrate

    /// Discrete bitrate steps for the surfaces with no Slider (tvOS pushed pickers, the gamepad
    /// settings' left/right cycling), up to the same 3 Gbps ceiling the slider has.
    static let bitratePresets: [(label: String, tag: Int)] = [
        ("Automatic", 0),
        ("10 Mbps", 10_000),
        ("20 Mbps", 20_000),
        ("40 Mbps", 40_000),
        ("80 Mbps", 80_000),
        ("150 Mbps", 150_000),
        ("300 Mbps", 300_000),
        ("500 Mbps", 500_000),
        ("1 Gbps", 1_000_000),
        ("1.5 Gbps", 1_500_000),
        ("2 Gbps", 2_000_000),
        ("3 Gbps", 3_000_000),
    ]

    /// The presets plus the currently stored value when it isn't one of them (set via the touch
    /// slider or a synced device) — so the current choice stays visible/selectable.
    static func bitrateOptions(current: Int) -> [(label: String, tag: Int)] {
        var options = bitratePresets
        if !options.contains(where: { $0.tag == current }) {
            options.insert(
                (SpeedTestSheet.mbpsLabel(kbps: current) + " (custom)", current), at: 1)
        }
        return options
    }

    // MARK: - Controllers

    /// "Use controller" choices: Automatic, every forwardable controller, and — so a stale pin
    /// stays visible instead of leaving the selection tag-less — any pinned id that is NOT among
    /// the selectable (extended) entries, present-but-unusable included.
    @MainActor
    static func controllerOptions(_ gamepads: GamepadManager) -> [(label: String, tag: String)] {
        let selectable = gamepads.controllers.filter(\.isExtended)
        var options: [(label: String, tag: String)] = [("Automatic", "")]
        options += selectable.map { ($0.name, $0.id) }
        if !gamepads.preferredID.isEmpty,
           !selectable.contains(where: { $0.id == gamepads.preferredID }) {
            options.append(("Unavailable controller", gamepads.preferredID))
        }
        return options
    }

    #if os(iOS) || os(macOS)
    // MARK: - Stream mode (iOS + macOS pickers; tvOS builds its own preset list)

    /// 16:9 then ultrawide presets; the device's native mode is prepended by `resolutionModes`.
    static let resolutionPresets: [(name: String, w: Int, h: Int)] = [
        ("720p", 1280, 720),
        ("1080p", 1920, 1080),
        ("1440p", 2560, 1440),
        ("4K", 3840, 2160),
        ("Ultrawide 1080p", 2560, 1080),
        ("Ultrawide 1440p", 3440, 1440),
        ("Super ultrawide", 5120, 1440),
    ]

    /// This device's native mode first, then the presets, deduped by dimensions (native wins a
    /// tie).
    @MainActor
    static func resolutionModes() -> [(name: String, w: Int, h: Int)] {
        var native: [(name: String, w: Int, h: Int)] = []
        #if os(iOS)
        let bounds = UIScreen.main.nativeBounds // portrait-oriented pixels
        native = [("This device",
                   Int(max(bounds.width, bounds.height)),
                   Int(min(bounds.width, bounds.height)))]
        #else
        if let screen = NSScreen.main {
            let scale = screen.backingScaleFactor
            native = [("This display",
                       Int(screen.frame.width * scale),
                       Int(screen.frame.height * scale))]
        }
        #endif
        var seen = Set<String>()
        return (native + resolutionPresets).filter { seen.insert("\($0.w)x\($0.h)").inserted }
    }

    /// Refresh rates the device can actually display (no point asking the host to render frames
    /// the screen can't show), plus any stored custom value so it stays selectable.
    @MainActor
    static func refreshRates(including current: Int) -> [Int] {
        #if os(iOS)
        let maxHz = UIScreen.main.maximumFramesPerSecond
        #else
        let maxHz = NSScreen.main?.maximumFramesPerSecond ?? 60
        #endif
        var rates = [60, 120, 240].filter { $0 <= maxHz }
        if rates.isEmpty { rates = [maxHz] }
        if !rates.contains(current) { rates.append(current) }
        return rates.sorted()
    }
    #endif
}
