import pytest

from clarabot_nano.common.auth.handler import ServerAuthenticator
from clarabot_nano.common.crypto.keyring import NanoSelfAccountKeyring
from clarabot_nano.utility.serialize import msgpack_loads


@pytest.fixture
def constant_self_kr():
    return NanoSelfAccountKeyring.load_internal(
        {
            "id": "RRRR222",
            "public_keys": {
                "1": b"5\x10\xd7\xe5t\x1c\x84\xb9rE\x06\xb6m`\xe6\x91\x0c\xe0\xa5"
                b"%\xdbn\xbc.\xdc\x88\xa5\\\xd9\x01\x17\x0b",
                "2": b"\x96\xec\xabsKX\xcd\x86f\x9cT+\x06\xa8\xb4\x9cx8\x82\xa4\x1aUu\xdd\x919\xcf\x19\xed\xe51G",
            },
            "secret_keys": {
                "1": b"+\xc5|\xa4\x08/\x82l3\xc1\xfc\x93\x8f\xdb\x11\x19\xf6\\\xb3"
                b"\xfbF\xbe\xf3\xd3\xb2%\x85\x1c_\xb9\x08\xf1",
                "2": b"\xd9lA\xd1\tb\xee[\n\x82\x9f\xff\x920#\xd5\xf8\x0b\xe0\x10\xb1K\xe0c\xa2\x9aT\xa3w\xfa}\x13",
                "3": b"\xdf\x1f\x10\x8a\xe7\xac\xbe\xee5\xfcg\xc0\xd2\x9bR\x12\x9a2"
                b"\x13\x03\xcak\xfft%\x14\x11\xaf\xe44\xa73",
            },
        }
    )


@pytest.fixture
def constant_keys():
    sk = b"y\xaf\x0e\xd4\xc2\x1b.\x044\xdd:!U\xba\xa0\xca"
    ck = b"\xcb\xfcw\xaae=\xcam$o\x82Y2\x03\xb2\x1c\xc5^\x9a\n\x07X!~\xcd4\xd1K\x83\xc41q"
    salt = b"0v\x06\xfb\xbe42\xa8F\\\x99\xbb\xdc3\xb0N"
    return sk, ck, salt


@pytest.fixture
def constant_combined_v1():
    return (
        b"\xaa*\x1d\xbb\xee8nG\r\t\xed\x82\xe1-\xba\xab\xf3\x94\x18`\xf1<h\xae"
        b"N\n\xe1\xe7\xca\x90D/\x01\x8f\x16\xf1\xb9\x8ag\xe9\xbf\x0eU\xf0&@\xf8\xdc"
        b"-/\xc6\xea\xffF4\xb2=0C\xeb\xd6\x98q+"
    )


@pytest.fixture
def local_storage_v1():
    return (
        b"\x82\xa7self_kr\xc4\xa1jkb\xcfN\x19\xd3i\xda_\x8br\xc7\xcc\xfb\x80\xa8\xebg|\x81,T\x9d\xe7\xf8\xf5"
        b"\xc9\x04\xd4\x82\xc5\x14\xfb\xbe{\xf9\x9d@\x08\x93h\x1a\x84w4h\xb7x\xe3\xdb\xc8_g\x1c\xa6\xdb\xa8"
        b"\xa5\xb2\xff\xd4_??([\x9db\xa8\xbd\x9f\x0b2\xf8\xa6Q\xe0\xf8\xee\xec\x9fE\x1f&\xc2\x8e\x14X4$\xfc"
        b'\x1c\x98I5%\x810\xee\xd9\xc1\xa6\xe9\xac\xa5\x1c\x08\x91z\xfc\xf5\x01\x9c*\xf1O\xe5p"8\x8b\xd0-\x84'
        b"\x87\x9c\r\x82\x07\xae\xb5`\x1c\xd1\xd8\x9ei\x1f\xcb\x9d\x9cc_\xc1\x94.C#\x89)3\xb8\x10o\xa6(\x14z"
        b"\xedN\xb2client_session_key\xc4 \xcb\xfcw\xaae=\xcam$o\x82Y2\x03\xb2\x1c\xc5^\x9a\n\x07X!~\xcd4"
        b"\xd1K\x83\xc41q"
    )


@pytest.fixture
def constant_combined_v2():
    return (
        b'u$\x9b,\xa3\x0e\xd1\xdcX\xf1\x16\xcfu\xd9\x18"y\xcd\xfe\xe7\x9f\x00\xf2;'
        b"7\xaaU\xe8n\x1f\xe0G1\xb6\x11O\x07\x8d\xae\xd4\x14D\xea\xa9\x84F/0"
        b"q\xfd\xab\xb0E\xacO&l\x99/n\x9dN\x02\xae"
    )


@pytest.fixture
def local_storage_v2():
    return (
        b'\x83\xa7self_kr\xc4\xa1;4\xaa/o\xef"Kf]\x04\xe6[\xc2T\x05Zta\x90\xd9\xa5w\x95\x98\xc8z\xe0\xb6\x85\x98'
        b"\x1e\xea$\xcd\x1f\x81&\x944\xb1\x0b\xd3\xfb\xe2|Lf, \r[[\xd6;\x1ekZ\xc0(\x89\xd0\xff\x0e\x92\xf7t%Hi\x07"
        b"am\xf4\xe5\x95GgH3\x15)#\x1d\x8e^7lu\xbf\xd7\x13hk\xe1N\xf2V\xb1\xe2.\x9f_\nSN\xf5\x0f\xb6\xc1u\xe9\xc3."
        b'r\x18lF\xb8q\xd3\x8b\x92\xe5\xe5[`\xffw\xd1\x1c"(\x1a\xcb\xe2\xc3\xf1k?\x01u\x81\x18\xb7\n\x0b\x7f\x05'
        b"\xec\xfaWCs\tq>\x92\xc5\x9a9\xb2client_session_key\xc4 \xcb\xfcw\xaae=\xcam$o\x82Y2\x03\xb2\x1c\xc5^\x9a"
        b"\n\x07X!~\xcd4\xd1K\x83\xc41q\xa4salt\xc4\x100v\x06\xfb\xbe42\xa8F\\\x99\xbb\xdc3\xb0N"
    )


def test_server_authenticator_local_security(
    tmp_path,
    constant_keys,
    constant_self_kr,
    constant_combined_v1,
    local_storage_v1,
    constant_combined_v2,
    local_storage_v2,
):
    constant_sk, constant_ck, constant_salt = constant_keys
    local_storages = [local_storage_v1, local_storage_v2]
    store_path = tmp_path / "_store"
    sa = ServerAuthenticator(None, None, None, store_path)

    # check derivation consistency
    assert sa._combine_server_and_client_keys(constant_sk, constant_ck, None) == constant_combined_v1
    assert sa._combine_server_and_client_keys(constant_sk, constant_ck, constant_salt) == constant_combined_v2

    # check loading all versions
    for ls_data in local_storages:
        sa._local_storage_path().write_bytes(ls_data)
        tmp = sa._read_local_storage(constant_sk)[sa.SELF_KR].dump_internal(skip_secret_keys=False)
        assert tmp == constant_self_kr.dump_internal(skip_secret_keys=False), str(tmp)

    # check safe writing current version
    sa._write_local_storage(constant_sk, constant_self_kr)
    tmp = sa._local_storage_path().read_bytes()
    assert all(tmp != ls_data for ls_data in local_storages)
    new_ls = msgpack_loads(tmp)
    assert set(new_ls.keys()) == {"self_kr", "client_session_key", "salt"}
    tmp = sa._read_local_storage(constant_sk)[sa.SELF_KR].dump_internal(skip_secret_keys=False)
    assert tmp == constant_self_kr.dump_internal(skip_secret_keys=False), str(tmp)
