import XCTest
@testable import Rosetta

final class SearchRoutingTests: XCTestCase {
    func testResponseRoutesToMatchingChannel() {
        let router = SearchPacketRouter()
        let uiChannel = SearchPacketChannel.ui(UUID())

        var uiHits = 0
        var userInfoHits = 0
        var unscopedHits = 0

        _ = router.addHandler(channel: uiChannel) { _ in uiHits += 1 }
        _ = router.addHandler(channel: .userInfo) { _ in userInfoHits += 1 }
        _ = router.addHandler(channel: .unscoped) { _ in unscopedHits += 1 }

        router.enqueueOutgoingRequest(channel: uiChannel)
        let firstRouted = router.dispatchIncomingResponse(PacketSearch())
        XCTAssertEqual(firstRouted, uiChannel)
        XCTAssertEqual(uiHits, 1)
        XCTAssertEqual(userInfoHits, 0)
        XCTAssertEqual(unscopedHits, 1)

        router.enqueueOutgoingRequest(channel: .userInfo)
        let secondRouted = router.dispatchIncomingResponse(PacketSearch())
        XCTAssertEqual(secondRouted, .userInfo)
        XCTAssertEqual(uiHits, 1)
        XCTAssertEqual(userInfoHits, 1)
        XCTAssertEqual(unscopedHits, 2)
    }

    func testInterleavingUiAndUserInfoDoesNotCrossTalk() {
        let router = SearchPacketRouter()
        let uiA = SearchPacketChannel.ui(UUID())
        let uiB = SearchPacketChannel.ui(UUID())

        var uiAHits = 0
        var uiBHits = 0
        var userInfoHits = 0

        _ = router.addHandler(channel: uiA) { _ in uiAHits += 1 }
        _ = router.addHandler(channel: uiB) { _ in uiBHits += 1 }
        _ = router.addHandler(channel: .userInfo) { _ in userInfoHits += 1 }

        router.enqueueOutgoingRequest(channel: uiA)
        router.enqueueOutgoingRequest(channel: .userInfo)
        router.enqueueOutgoingRequest(channel: uiB)

        _ = router.dispatchIncomingResponse(PacketSearch())
        _ = router.dispatchIncomingResponse(PacketSearch())
        _ = router.dispatchIncomingResponse(PacketSearch())

        XCTAssertEqual(uiAHits, 1)
        XCTAssertEqual(userInfoHits, 1)
        XCTAssertEqual(uiBHits, 1)
    }

    func testResetPendingClearsRoutingState() {
        let router = SearchPacketRouter()
        let uiChannel = SearchPacketChannel.ui(UUID())

        var uiHits = 0
        var unscopedHits = 0

        _ = router.addHandler(channel: uiChannel) { _ in uiHits += 1 }
        _ = router.addHandler(channel: .unscoped) { _ in unscopedHits += 1 }

        router.enqueueOutgoingRequest(channel: uiChannel)
        XCTAssertEqual(router.pendingCount, 1)

        router.resetPending()
        XCTAssertEqual(router.pendingCount, 0)

        let routed = router.dispatchIncomingResponse(PacketSearch())
        XCTAssertEqual(routed, .unscoped)
        XCTAssertEqual(uiHits, 0)
        XCTAssertEqual(unscopedHits, 1)
    }

    func testFallbackToUnscopedWhenNoPending() {
        let router = SearchPacketRouter()
        var unscopedHits = 0
        var userInfoHits = 0

        _ = router.addHandler(channel: .unscoped) { _ in unscopedHits += 1 }
        _ = router.addHandler(channel: .userInfo) { _ in userInfoHits += 1 }

        let routed = router.dispatchIncomingResponse(PacketSearch())
        XCTAssertEqual(routed, .unscoped)
        XCTAssertEqual(unscopedHits, 1)
        XCTAssertEqual(userInfoHits, 0)
    }
}
