import stat
from contextlib import asynccontextmanager
from pathlib import Path

import safe_radix32
from clarabot_nano_common.utility.serialize import msgpack_dumps

from clarabot_nano_tests.testing.config import room_blocks_from_room_data
from clarabot_nano_tests.testing.gateway import start_nano_wait_gateway, do_gateway_login


def check_fs_recursive(remote: Path, local: Path):
    rs = remote.stat()  # allow symlink resolution
    ls = local.lstat()
    assert stat.S_ISDIR(rs.st_mode) is stat.S_ISDIR(ls.st_mode), f"{remote} {local}"
    assert stat.S_ISREG(rs.st_mode) is stat.S_ISREG(ls.st_mode), f"{remote} {local}"
    if stat.S_ISDIR(rs.st_mode):
        r_items = sorted(remote.iterdir(), key=lambda x: x.name)
        l_items = sorted(local.iterdir(), key=lambda x: x.name)
        assert len(r_items) == len(l_items), f"{[x.name for x in r_items]} {[x.name for x in l_items]}"
        for remote_item, local_item in zip(r_items, l_items):
            assert remote_item.name == local_item.name, f"{remote_item} {local_item}"
            check_fs_recursive(remote_item, local_item)
    else:
        assert rs.st_size == ls.st_size, f"{remote} {local}"
        assert rs.st_mtime == ls.st_mtime, f"{remote} {local}"
        assert remote.read_bytes() == local.read_bytes()


@asynccontextmanager
async def run_nano_setup_drive(
    testing_server_manager,
    testing_client_manager,
    user_app_dirs,
    dev_nano_root_dir,
    user_data,
    drive_path,
    room_data,
    extra_env=None,
    salt="",
):
    user_wsc = await testing_client_manager.create_logged_in_wsc(user_data)
    assert not user_wsc.ws.closed
    async with start_nano_wait_gateway(
        testing_server_manager, user_app_dirs, dev_nano_root_dir, "waiting-config", extra_env=extra_env
    ) as (pm, debug_info, gateway_port, gateway_key):
        # successful login
        session_id = await do_gateway_login(
            testing_server_manager, pm, debug_info, gateway_port, gateway_key, user_data
        )
        await testing_server_manager.wait_nano_bind(user_data["account_id"], {session_id: set()})
        nano_id = await testing_server_manager.get_nano_id_by_nano_session_id(user_data["account_id"], session_id)

        # set admin password with mutation id (initial allowed without admin session)
        a_pwd = f"pw{salt}-{user_data['account_id']}"
        mut_name = f"dbg{salt}-{user_data['account_id']}"
        await testing_client_manager.nano_request_response(
            msgpack_dumps(
                await testing_client_manager.prepare_request_with_mutation_id(
                    {"type": "A-CH-PWD", "new_password": a_pwd},
                    mut_name,
                    None,
                    nano_id,
                    user_wsc,
                    user_data["_acc_kr"],
                    user_data["_acc_kr"],
                )
            ),
            None,
            nano_id,
            user_wsc,
            user_data["_acc_kr"],
            user_data["_acc_kr"],
        )
        # create admin-session
        a_sess = await testing_client_manager.new_admin_session_request(
            a_pwd, mut_name, None, nano_id, user_wsc, user_data["_acc_kr"], user_data["_acc_kr"]
        )
        # create drive
        drive_req = {"type": "A-D-CREATE", "path": str(drive_path)}
        await testing_client_manager.single_response_admin_request(
            drive_req, mut_name, a_sess, None, nano_id, user_wsc, user_data["_acc_kr"], user_data["_acc_kr"]
        )
        # attach with verified blocks
        await testing_client_manager.single_response_admin_request(
            {
                "type": "A-D-ATTACH",
                "path": str(drive_path),
                "target_room_id": safe_radix32.encode_fw(room_data["id"]),
                "room_blocks": room_blocks_from_room_data(room_data),
            },
            mut_name,
            a_sess,
            None,
            nano_id,
            user_wsc,
            user_data["_acc_kr"],
            user_data["_acc_kr"],
        )

        yield user_wsc, a_sess, mut_name, nano_id
