//
//  DeepLinkHandlerTests.swift
//  SportsTimeTests
//
//  TDD specification tests for DeepLinkHandler URL parsing.
//

import Testing
import Foundation
@testable import SportsTime

@Suite("DeepLinkHandler")
@MainActor
struct DeepLinkHandlerTests {

    private let handler = DeepLinkHandler.shared

    // MARK: - Specification Tests: parseURL

    /// - Expected Behavior: Valid poll URL returns .poll with share code
    @Test("parseURL: sportstime://poll/{code} returns poll destination")
    func parseURL_validPollURL() {
        let url = URL(string: "sportstime://poll/ABC123")!
        let result = handler.parseURL(url)

        if case .poll(let shareCode) = result {
            #expect(shareCode == "ABC123")
        } else {
            Issue.record("Expected .poll destination")
        }
    }

    /// - Expected Behavior: Poll URL normalizes code to uppercase
    @Test("parseURL: normalizes share code to uppercase")
    func parseURL_normalizesToUppercase() {
        let url = URL(string: "sportstime://poll/abc123")!
        let result = handler.parseURL(url)

        if case .poll(let shareCode) = result {
            #expect(shareCode == "ABC123")
        } else {
            Issue.record("Expected .poll destination")
        }
    }

    /// - Expected Behavior: Invalid scheme returns nil
    @Test("parseURL: wrong scheme returns nil")
    func parseURL_wrongScheme() {
        let httpURL = URL(string: "http://poll/ABC123")!
        #expect(handler.parseURL(httpURL) == nil)

        let httpsURL = URL(string: "https://poll/ABC123")!
        #expect(handler.parseURL(httpsURL) == nil)
    }

    /// - Expected Behavior: Empty path returns nil
    @Test("parseURL: empty path returns nil")
    func parseURL_emptyPath() {
        let url = URL(string: "sportstime://")!
        #expect(handler.parseURL(url) == nil)
    }

    /// - Expected Behavior: Unknown path returns nil
    @Test("parseURL: unknown path returns nil")
    func parseURL_unknownPath() {
        let url = URL(string: "sportstime://unknown/ABC123")!
        #expect(handler.parseURL(url) == nil)
    }

    /// - Expected Behavior: Poll path without code returns nil
    @Test("parseURL: poll path without code returns nil")
    func parseURL_pollWithoutCode() {
        let url = URL(string: "sportstime://poll")!
        #expect(handler.parseURL(url) == nil)

        let urlWithSlash = URL(string: "sportstime://poll/")!
        #expect(handler.parseURL(urlWithSlash) == nil)
    }

    // MARK: - Specification Tests: Share Code Validation

    /// - Expected Behavior: Share code must be exactly 6 characters
    @Test("parseURL: validates share code length")
    func parseURL_validateCodeLength() {
        // Too short
        let shortURL = URL(string: "sportstime://poll/ABC12")!
        #expect(handler.parseURL(shortURL) == nil)

        // Too long
        let longURL = URL(string: "sportstime://poll/ABC1234")!
        #expect(handler.parseURL(longURL) == nil)

        // Exactly 6 - valid
        let validURL = URL(string: "sportstime://poll/ABC123")!
        #expect(handler.parseURL(validURL) != nil)
    }

    // MARK: - Invariant Tests

    /// - Invariant: Only sportstime:// scheme is valid
    @Test("Invariant: scheme must be sportstime")
    func invariant_schemeMustBeSportstime() {
        let validURL = URL(string: "sportstime://poll/ABC123")!
        #expect(handler.parseURL(validURL) != nil)

        // Various invalid schemes
        let schemes = ["http", "https", "file", "ftp", "app"]
        for scheme in schemes {
            let url = URL(string: "\(scheme)://poll/ABC123")!
            #expect(handler.parseURL(url) == nil, "Scheme '\(scheme)' should be rejected")
        }
    }

    /// - Invariant: Path must start with recognized destination type
    @Test("Invariant: path must be recognized destination")
    func invariant_pathMustBeRecognized() {
        // Only 'poll' is recognized
        let pollURL = URL(string: "sportstime://poll/ABC123")!
        #expect(handler.parseURL(pollURL) != nil)

        // Other paths should fail
        let otherPaths = ["trip", "game", "stadium", "user", "settings"]
        for path in otherPaths {
            let url = URL(string: "sportstime://\(path)/ABC123")!
            #expect(handler.parseURL(url) == nil, "Path '\(path)' should not be recognized")
        }
    }
}

// MARK: - DeepLinkDestination Tests

@Suite("DeepLinkDestination")
@MainActor
struct DeepLinkDestinationTests {

    // MARK: - Specification Tests: Equatable

    @Test("Equatable: poll destinations with same code are equal")
    func equatable_sameCode() {
        let dest1 = DeepLinkDestination.poll(shareCode: "ABC123")
        let dest2 = DeepLinkDestination.poll(shareCode: "ABC123")

        #expect(dest1 == dest2)
    }

    @Test("Equatable: poll destinations with different codes are not equal")
    func equatable_differentCodes() {
        let dest1 = DeepLinkDestination.poll(shareCode: "ABC123")
        let dest2 = DeepLinkDestination.poll(shareCode: "XYZ789")

        #expect(dest1 != dest2)
    }

    // MARK: - Specification Tests: Properties

    @Test("poll: shareCode returns associated value")
    func poll_shareCode() {
        let dest = DeepLinkDestination.poll(shareCode: "TEST99")

        if case .poll(let code) = dest {
            #expect(code == "TEST99")
        } else {
            Issue.record("Expected poll case")
        }
    }
}
