import Testing
@testable import SessionCore

/// T-iOS-11 · KeyByteMap (plan §7). The key-bar byte table must mirror
/// `public/keybar.ts` `KEY_MAP` byte-for-byte — every entry is compared
/// against an independently written expectation (raw scalar values, not the
/// implementation's own literals) so a typo in either side turns the suite red.
@Suite("KeyByteMap")
struct KeyByteMapTests {
    /// Expected byte strings, transcribed key-by-key from public/keybar.ts
    /// KEY_MAP (the web client's single source of truth). Values are built
    /// from Unicode scalars so this table cannot share a typo with the
    /// implementation's string literals.
    private static let expectedBytesByKey: [KeyByteMap.Key: [UInt8]] = [
        .esc: [0x1B], // '\x1b'
        .escEsc: [0x1B, 0x1B], // '\x1b\x1b'
        .shiftTab: [0x1B, 0x5B, 0x5A], // '\x1b[Z'
        .arrowUp: [0x1B, 0x5B, 0x41], // '\x1b[A'
        .arrowDown: [0x1B, 0x5B, 0x42], // '\x1b[B'
        .arrowLeft: [0x1B, 0x5B, 0x44], // '\x1b[D'
        .arrowRight: [0x1B, 0x5B, 0x43], // '\x1b[C'
        .enter: [0x0D], // '\r' — carriage return, NOT '\n'
        .ctrlC: [0x03],
        .ctrlR: [0x12],
        .ctrlO: [0x0F],
        .ctrlL: [0x0C],
        .ctrlT: [0x14],
        .ctrlB: [0x02],
        .ctrlD: [0x04],
        .tab: [0x09], // '\t'
        .slash: [0x2F], // '/'
    ]

    @Test("every key resolves to the exact bytes of public/keybar.ts KEY_MAP")
    func everyEntryMatchesWebKeyMapByteForByte() {
        for key in KeyByteMap.Key.allCases {
            // Arrange
            let expected = Self.expectedBytesByKey[key]

            // Act
            let actual = Array(KeyByteMap.bytes(for: key).utf8)

            // Assert
            #expect(actual == expected, "bytes mismatch for \(key.rawValue)")
        }
    }

    @Test("the table covers exactly the 17 web KEY_MAP entries — no more, no less")
    func tableCoversExactlyTheWebKeyMapEntries() {
        #expect(KeyByteMap.Key.allCases.count == Self.expectedBytesByKey.count)
        #expect(Set(KeyByteMap.Key.allCases).count == KeyByteMap.Key.allCases.count)
    }

    @Test("Enter sends carriage return (0x0D), never linefeed (gotcha: \\r not \\n)")
    func enterIsCarriageReturnNotLinefeed() {
        #expect(KeyByteMap.bytes(for: .enter) == "\r")
        #expect(KeyByteMap.bytes(for: .enter) != "\n")
    }

    @Test("arrow CSI letters: up=A down=B left=D right=C (left/right are the classic swap)")
    func arrowFinalLettersAreNotSwapped() {
        #expect(KeyByteMap.bytes(for: .arrowUp).hasSuffix("A"))
        #expect(KeyByteMap.bytes(for: .arrowDown).hasSuffix("B"))
        #expect(KeyByteMap.bytes(for: .arrowLeft).hasSuffix("D"))
        #expect(KeyByteMap.bytes(for: .arrowRight).hasSuffix("C"))
    }

    @Test("raw values mirror the web KEY_MAP property names (stable lookup identity)")
    func rawValuesMirrorWebKeyNames() {
        let expectedNames = [
            "esc", "escEsc", "shiftTab", "arrowUp", "arrowDown", "arrowLeft",
            "arrowRight", "enter", "ctrlC", "ctrlR", "ctrlO", "ctrlL", "ctrlT",
            "ctrlB", "ctrlD", "tab", "slash",
        ]
        #expect(KeyByteMap.Key.allCases.map(\.rawValue) == expectedNames)
    }
}
