from __future__ import annotations

from pymulator.core.uds import ServiceId

from .conftest import load_handler, make_message


def test_uds_session_control_and_security():
    session = load_handler("uds.json")
    resp = session.handle_request(make_message(session.arbitration_id, [ServiceId.diagnostic_session_control, 0x03]))
    assert resp[:2] == [0x50, 0x03]

    seed_resp = session.handle_request(make_message(session.arbitration_id, [ServiceId.security_access, 0x01]))
    assert seed_resp[:2] == [0x67, 0x01]
    assert seed_resp[2:] == [0xAA, 0xBB]

    key_resp = session.handle_request(make_message(session.arbitration_id, [ServiceId.security_access, 0x02, 0xCC, 0xDD]))
    assert key_resp == [0x67, 0x02]


def test_uds_read_write_and_dynamic_did():
    session = load_handler("uds.json")
    vin_resp = session.handle_request(make_message(session.arbitration_id, [ServiceId.read_data_by_identifier, 0xF1, 0x90]))
    assert vin_resp[:3] == [0x62, 0xF1, 0x90]
    assert bytes(vin_resp[3:]).decode("utf-8") == "TESTVIN123456789"

    write_resp = session.handle_request(make_message(session.arbitration_id, [ServiceId.write_data_by_identifier, 0xF1, 0x87, 0x99, 0x88]))
    assert write_resp == [0x6E, 0xF1, 0x87]
    read_resp = session.handle_request(make_message(session.arbitration_id, [ServiceId.read_data_by_identifier, 0xF1, 0x87]))
    assert read_resp == [0x62, 0xF1, 0x87, 0x99, 0x88]

    define_resp = session.handle_request(
        make_message(
            session.arbitration_id,
            [ServiceId.dynamically_define_data_identifier, 0x01, 0xF3, 0x00, 0xF1, 0x90, 0x01, 0x02],
        )
    )
    assert define_resp == [0x6C, 0x01, 0xF3, 0x00]

    dynamic_resp = session.handle_request(make_message(session.arbitration_id, [ServiceId.read_data_by_identifier, 0xF3, 0x00]))
    assert dynamic_resp == [0x62, 0xF3, 0x00, 0x54, 0x45]


def test_uds_download_transfer_and_dtcs():
    session = load_handler("uds.json")
    session.handle_request(make_message(session.arbitration_id, [ServiceId.diagnostic_session_control, 0x03]))

    download_resp = session.handle_request(
        make_message(
            session.arbitration_id,
            [ServiceId.request_download, 0x00, 0x22, 0x10, 0x00, 0x00, 0x10],
        )
    )
    assert download_resp == [0x74, 0x20, 0x00, 0x08]

    transfer_resp = session.handle_request(
        make_message(
            session.arbitration_id,
            [ServiceId.transfer_data, 0x01, 1, 2, 3, 4, 5, 6, 7, 8],
        )
    )
    assert transfer_resp == [0x76, 0x01]

    exit_resp = session.handle_request(make_message(session.arbitration_id, [ServiceId.request_transfer_exit]))
    assert exit_resp == [0x77]

    dtc_resp = session.handle_request(
        make_message(session.arbitration_id, [ServiceId.read_dtc_information, 0x02, 0xFF])
    )
    assert dtc_resp == [0x59, 0x02, 0x08, 1, 2, 3, 0x08]


def test_uds_scaling_periodic_io_and_memory():
    session = load_handler("uds.json")

    scaling = session.handle_request(
        make_message(session.arbitration_id, [ServiceId.read_scaling_data_by_identifier, 0xF1, 0x90])
    )
    assert scaling[:3] == [0x64, 0xF1, 0x90]
    assert bytes(scaling[3:]).decode("utf-8") == "TESTVIN123456789"

    periodic = session.handle_request(
        make_message(session.arbitration_id, [ServiceId.read_data_by_periodic_identifier, 0x01, 0xF1, 0x90])
    )
    assert periodic == [0x6A, 0x01, 0xF1, 0x90]

    io_resp = session.handle_request(
        make_message(session.arbitration_id, [ServiceId.input_output_control_by_identifier, 0xF1, 0x87, 0x55])
    )
    assert io_resp == [0x6F, 0xF1, 0x87, 0x55]
    io_read = session.handle_request(
        make_message(session.arbitration_id, [ServiceId.read_data_by_identifier, 0xF1, 0x87])
    )
    assert io_read == [0x62, 0xF1, 0x87, 0x55]

    write_mem = session.handle_request(
        make_message(session.arbitration_id, [ServiceId.write_memory_by_address, 0x12, 0x10, 0x00, 0x02, 0xDE, 0xAD])
    )
    assert write_mem == [0x7D, 0x10, 0x00, 0x02]
    read_mem = session.handle_request(
        make_message(session.arbitration_id, [ServiceId.read_memory_by_address, 0x12, 0x10, 0x00, 0x02])
    )
    assert read_mem == [0x63, 0xDE, 0xAD]
