import Foundation
import Testing
import NucleicProtocol
import NucleicTailnet

@testable import NucleicCore

@Suite struct SyncTransportSettingTests {
    private func freshDefaults() -> UserDefaults {
        let suite = "SyncTransportSettingTests-\(UUID().uuidString)"
        let defaults = UserDefaults(suiteName: suite)!
        defaults.removePersistentDomain(forName: suite)
        return defaults
    }

    @Test func defaultsToLAN() {
        #expect(SyncTransportSetting.resolve(environment: [:], defaults: freshDefaults()) == .lan)
    }

    @Test func readsTheSettingsPickerValue() {
        let defaults = freshDefaults()
        defaults.set(SyncTransportHint.tailnet.rawValue, forKey: SyncTransportSetting.defaultsKey)
        #expect(SyncTransportSetting.resolve(environment: [:], defaults: defaults) == .tailnet)
    }

    @Test func envOverridesDefaults() {
        let defaults = freshDefaults()
        defaults.set(SyncTransportHint.lan.rawValue, forKey: SyncTransportSetting.defaultsKey)
        let env = [SyncTransportSetting.envKey: SyncTransportHint.tailnet.rawValue]
        #expect(SyncTransportSetting.resolve(environment: env, defaults: defaults) == .tailnet)
    }

    @Test func unknownValueFallsBackToLAN() {
        let env = [SyncTransportSetting.envKey: "quic"]
        #expect(SyncTransportSetting.resolve(environment: env, defaults: freshDefaults()) == .lan)
    }

    // MARK: Multi-select method set (mesh P1)

    @Test func enabledSetDefaultsToLAN() {
        #expect(SyncTransportSetting.resolveEnabled(environment: [:], defaults: freshDefaults()) == [.lan])
    }

    @Test func enabledSetReadsTheCheckboxValue() {
        let defaults = freshDefaults()
        defaults.set("lan,tailnet", forKey: SyncTransportSetting.setDefaultsKey)
        #expect(SyncTransportSetting.resolveEnabled(environment: [:], defaults: defaults) == [.lan, .tailnet])
    }

    @Test func enabledSetEnvOverridesDefaults() {
        let defaults = freshDefaults()
        defaults.set("lan", forKey: SyncTransportSetting.setDefaultsKey)
        let env = [SyncTransportSetting.setEnvKey: "tailnet"]
        #expect(SyncTransportSetting.resolveEnabled(environment: env, defaults: defaults) == [.tailnet])
    }

    @Test func enabledSetMigratesLegacySingleChoice() {
        // Legacy tailnet mode always ran LAN alongside — the migrated set preserves that.
        let defaults = freshDefaults()
        defaults.set(SyncTransportHint.tailnet.rawValue, forKey: SyncTransportSetting.defaultsKey)
        #expect(SyncTransportSetting.resolveEnabled(environment: [:], defaults: defaults) == [.lan, .tailnet])

        let lanDefaults = freshDefaults()
        lanDefaults.set(SyncTransportHint.lan.rawValue, forKey: SyncTransportSetting.defaultsKey)
        #expect(SyncTransportSetting.resolveEnabled(environment: [:], defaults: lanDefaults) == [.lan])

        // A stale relay value (the picker never enabled it) degrades to LAN.
        let relayDefaults = freshDefaults()
        relayDefaults.set(SyncTransportHint.relay.rawValue, forKey: SyncTransportSetting.defaultsKey)
        #expect(SyncTransportSetting.resolveEnabled(environment: [:], defaults: relayDefaults) == [.lan])
    }

    @Test func enabledSetIgnoresJunkAndFallsBackToLegacy() {
        let defaults = freshDefaults()
        defaults.set("quic, smoke-signals", forKey: SyncTransportSetting.setDefaultsKey)
        defaults.set(SyncTransportHint.tailnet.rawValue, forKey: SyncTransportSetting.defaultsKey)
        // All tokens unparseable → empty set → legacy migration applies.
        #expect(SyncTransportSetting.resolveEnabled(environment: [:], defaults: defaults) == [.lan, .tailnet])
    }

    @Test func enabledSetToleratesUnknownTokensAmongValidOnes() {
        let env = [SyncTransportSetting.setEnvKey: "lan, quic ,tailnet"]
        #expect(SyncTransportSetting.resolveEnabled(environment: env, defaults: freshDefaults()) == [.lan, .tailnet])
    }

    @Test func enabledSetSerializationIsStableAndRoundTrips() {
        let defaults = freshDefaults()
        SyncTransportSetting.saveEnabled([.tailnet, .lan], defaults: defaults)
        #expect(defaults.string(forKey: SyncTransportSetting.setDefaultsKey) == "lan,tailnet")
        #expect(SyncTransportSetting.resolveEnabled(environment: [:], defaults: defaults) == [.lan, .tailnet])
    }

    @Test func nodeNamesAreDNSLabelSafe() {
        #expect(TailnetConfig.nodeName(for: "Andrew's MacBook Pro") == "nucleic-andrew-s-macbook-pro")
        #expect(TailnetConfig.nodeName(for: "Mac", channel: "beta") == "nucleic-beta-mac")
        // Nothing usable in the name → stable fallback, never an empty label.
        #expect(TailnetConfig.nodeName(for: "😀🎉") == "nucleic-device")
    }
}
