import XCTest
@testable import Rosetta

@MainActor
final class CallAttachmentParityTests: XCTestCase {
    private var ctx: DBTestContext!
    private var packetSenderMock: CallAttachmentPacketSenderMock!

    private var ownPrivateKeyHex: String = ""
    private var ownPublicKey: String = ""
    private var peerPublicKey: String = ""

    override func setUpWithError() throws {
        let ownPair = try Self.makeKeyPair()
        let peerPair = try Self.makeKeyPair()

        ownPrivateKeyHex = ownPair.privateKeyHex
        ownPublicKey = ownPair.publicKeyHex
        peerPublicKey = peerPair.publicKeyHex

        ctx = DBTestContext(account: ownPublicKey)
        packetSenderMock = CallAttachmentPacketSenderMock()

        SessionManager.shared.testConfigureSessionForParityFlows(
            currentPublicKey: ownPublicKey,
            privateKeyHex: ownPrivateKeyHex
        )
        SessionManager.shared.packetFlowSender = packetSenderMock
        AttachmentCache.shared.privateKey = ownPrivateKeyHex
    }

    override func tearDownWithError() throws {
        ctx?.teardown()
        ctx = nil
        packetSenderMock = nil
        AttachmentCache.shared.privateKey = nil
        SessionManager.shared.testResetParityFlowDependencies()
    }

    func testCallDurationPreviewParserMatrix() {
        let tag = "aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb"

        XCTAssertEqual(AttachmentPreviewCodec.parseCallDurationSeconds("65"), 65)
        XCTAssertEqual(AttachmentPreviewCodec.parseCallDurationSeconds("\(tag)::125"), 125)
        XCTAssertEqual(AttachmentPreviewCodec.parseCallDurationSeconds("durationSec=42"), 42)
        XCTAssertEqual(AttachmentPreviewCodec.parseCallDurationSeconds("duration 33"), 33)
        XCTAssertEqual(AttachmentPreviewCodec.parseCallDurationSeconds("invalid"), 0)
    }

    func testSendCallAttachmentProducesType4WithDurationPreview() async throws {
        try await ctx.bootstrap()

        try await SessionManager.shared.sendCallAttachment(
            toPublicKey: peerPublicKey,
            durationSec: 87,
            opponentTitle: "Peer",
            opponentUsername: "peer"
        )

        XCTAssertEqual(packetSenderMock.sentMessages.count, 1)
        guard let packet = packetSenderMock.sentMessages.first else {
            XCTFail("Expected one outgoing call attachment packet")
            return
        }

        XCTAssertEqual(packet.attachments.count, 1)
        let attachment = packet.attachments[0]
        XCTAssertEqual(attachment.type, .call)
        XCTAssertEqual(attachment.preview, "87")
        XCTAssertEqual(attachment.blob, "")
    }

    private static func makeKeyPair() throws -> (privateKeyHex: String, publicKeyHex: String) {
        let mnemonic = try CryptoManager.shared.generateMnemonic()
        let pair = try CryptoManager.shared.deriveKeyPair(from: mnemonic)
        return (pair.privateKey.hexString, pair.publicKey.hexString)
    }
}

private final class CallAttachmentPacketSenderMock: PacketFlowSending {
    private(set) var sentMessages: [PacketMessage] = []

    func sendPacket(_ packet: any Packet) {
        if let message = packet as? PacketMessage {
            sentMessages.append(message)
        }
    }
}
