import Testing
@testable import bookstax

// MARK: - URL Validation

@Suite("OnboardingViewModel – URL Validation")
struct OnboardingViewModelURLTests {

    // MARK: Empty input

    @Test("Empty URL sets error and returns false")
    func emptyURL() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = ""
        #expect(vm.validateServerURL() == false)
        #expect(vm.serverURLError != nil)
    }

    @Test("Whitespace-only URL sets error and returns false")
    func whitespaceURL() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "   "
        #expect(vm.validateServerURL() == false)
        #expect(vm.serverURLError != nil)
    }

    // MARK: Auto-prefix https://

    @Test("URL without scheme gets https:// prepended")
    func autoprefixHTTPS() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "wiki.example.com"
        let result = vm.validateServerURL()
        #expect(result == true)
        #expect(vm.serverURLInput.hasPrefix("https://"))
    }

    @Test("URL already starting with https:// is left unchanged")
    func httpsAlreadyPresent() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "https://wiki.example.com"
        let result = vm.validateServerURL()
        #expect(result == true)
        #expect(vm.serverURLInput == "https://wiki.example.com")
    }

    @Test("URL starting with http:// is left as-is (not double-prefixed)")
    func httpNotDoublePrefixed() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "http://wiki.example.com"
        let result = vm.validateServerURL()
        #expect(result == true)
        #expect(vm.serverURLInput == "http://wiki.example.com")
    }

    // MARK: Trailing slash removal

    @Test("Trailing slash is stripped from URL")
    func trailingSlash() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "https://wiki.example.com/"
        _ = vm.validateServerURL()
        #expect(vm.serverURLInput == "https://wiki.example.com")
    }

    @Test("Multiple trailing slashes – only last slash stripped then accepted")
    func multipleSlashesInPath() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "https://wiki.example.com/path/"
        _ = vm.validateServerURL()
        #expect(vm.serverURLInput == "https://wiki.example.com/path")
    }

    // MARK: Successful validation

    @Test("Valid URL clears any previous error")
    func validURLClearsError() {
        let vm = OnboardingViewModel()
        vm.serverURLError = "Previous error"
        vm.serverURLInput = "https://books.mycompany.com"
        #expect(vm.validateServerURL() == true)
        #expect(vm.serverURLError == nil)
    }
}

// MARK: - isHTTP Flag

@Suite("OnboardingViewModel – isHTTP")
struct OnboardingViewModelHTTPTests {

    @Test("http:// URL sets isHTTP = true")
    func httpURL() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "http://wiki.local"
        #expect(vm.isHTTP == true)
    }

    @Test("https:// URL sets isHTTP = false")
    func httpsURL() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "https://wiki.local"
        #expect(vm.isHTTP == false)
    }

    @Test("Empty URL is not HTTP")
    func emptyNotHTTP() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = ""
        #expect(vm.isHTTP == false)
    }
}

// MARK: - isRemoteServer Detection

@Suite("OnboardingViewModel – isRemoteServer")
struct OnboardingViewModelRemoteTests {

    // MARK: Local / private addresses

    @Test("localhost is not remote")
    func localhost() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "http://localhost"
        #expect(vm.isRemoteServer == false)
    }

    @Test("127.0.0.1 is not remote")
    func loopback() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "http://127.0.0.1"
        #expect(vm.isRemoteServer == false)
    }

    @Test("IPv6 loopback ::1 is not remote")
    func ipv6Loopback() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "http://[::1]"
        #expect(vm.isRemoteServer == false)
    }

    @Test(".local mDNS host is not remote")
    func mdnsLocal() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "http://bookstack.local"
        #expect(vm.isRemoteServer == false)
    }

    @Test("Plain hostname without dots is not remote")
    func plainHostname() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "http://mywiki"
        #expect(vm.isRemoteServer == false)
    }

    @Test("10.x.x.x private range is not remote")
    func privateClass_A() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "http://10.0.1.50"
        #expect(vm.isRemoteServer == false)
    }

    @Test("192.168.x.x private range is not remote")
    func privateClass_C() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "http://192.168.1.100"
        #expect(vm.isRemoteServer == false)
    }

    @Test("172.16.x.x private range is not remote")
    func privateClass_B_low() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "http://172.16.0.1"
        #expect(vm.isRemoteServer == false)
    }

    @Test("172.31.x.x private range is not remote")
    func privateClass_B_high() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "http://172.31.255.255"
        #expect(vm.isRemoteServer == false)
    }

    @Test("172.15.x.x is outside private range and is remote")
    func justBelowPrivateClass_B() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "http://172.15.0.1"
        #expect(vm.isRemoteServer == true)
    }

    @Test("172.32.x.x is outside private range and is remote")
    func justAbovePrivateClass_B() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "http://172.32.0.1"
        #expect(vm.isRemoteServer == true)
    }

    // MARK: Remote addresses

    @Test("Public IP 8.8.8.8 is remote")
    func publicIP() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "http://8.8.8.8"
        #expect(vm.isRemoteServer == true)
    }

    @Test("Public domain with subdomain is remote")
    func publicDomain() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "https://wiki.mycompany.com"
        #expect(vm.isRemoteServer == true)
    }

    @Test("Top-level domain name is remote")
    func topLevelDomain() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = "https://bookstack.io"
        #expect(vm.isRemoteServer == true)
    }

    @Test("Empty URL is not remote")
    func emptyIsNotRemote() {
        let vm = OnboardingViewModel()
        vm.serverURLInput = ""
        #expect(vm.isRemoteServer == false)
    }
}
