import os
from datetime import datetime, timezone
from typing import Any

import orjson
from django.test import override_settings

from zerver.data_import.import_util import (
    SubscriberHandler,
    UploadRecordData,
    ZerverFieldsT,
    build_recipients,
)
from zerver.data_import.rocketchat import (
    build_custom_emoji,
    build_reactions,
    categorize_channels_and_map_with_id,
    convert_channel_data,
    convert_direct_message_group_data,
    convert_stream_subscription_data,
    do_convert_data,
    map_receiver_id_to_recipient_id,
    map_upload_id_to_upload_data,
    map_user_id_to_user,
    map_username_to_user_id,
    process_message_attachment,
    process_users,
    rocketchat_data_to_dict,
    separate_channel_private_and_livechat_messages,
    truncate_name,
)
from zerver.data_import.sequencer import IdMapper
from zerver.data_import.user_handler import UserHandler
from zerver.lib.emoji import name_to_codepoint
from zerver.lib.import_realm import do_import_realm
from zerver.lib.test_classes import ZulipTestCase
from zerver.models import Message, Reaction, Recipient, UserProfile
from zerver.models.realms import get_realm
from zerver.models.users import get_user


class RocketChatImporter(ZulipTestCase):
    def test_rocketchat_data_to_dict(self) -> None:
        fixture_dir_name = self.fixture_file_name("", "rocketchat_fixtures")
        rocketchat_data = rocketchat_data_to_dict(fixture_dir_name)
        self.assert_length(rocketchat_data, 7)

        self.assert_length(rocketchat_data["user"], 6)
        self.assertEqual(rocketchat_data["user"][2]["username"], "harry.potter")
        self.assert_length(rocketchat_data["user"][2]["__rooms"], 10)

        self.assert_length(rocketchat_data["room"], 16)
        self.assertEqual(rocketchat_data["room"][0]["_id"], "GENERAL")
        self.assertEqual(rocketchat_data["room"][0]["name"], "general")

        self.assert_length(rocketchat_data["message"], 87)
        self.assertEqual(rocketchat_data["message"][1]["msg"], "Hey everyone, how's it going??")
        self.assertEqual(rocketchat_data["message"][1]["rid"], "GENERAL")
        self.assertEqual(rocketchat_data["message"][1]["u"]["username"], "priyansh3133")

        self.assert_length(rocketchat_data["custom_emoji"]["emoji"], 3)
        self.assertEqual(rocketchat_data["custom_emoji"]["emoji"][0]["name"], "tick")

        self.assert_length(rocketchat_data["upload"]["upload"], 4)
        self.assertEqual(rocketchat_data["upload"]["upload"][0]["name"], "harry-ron.jpg")

    def test_map_user_id_to_user(self) -> None:
        fixture_dir_name = self.fixture_file_name("", "rocketchat_fixtures")
        rocketchat_data = rocketchat_data_to_dict(fixture_dir_name)

        user_id_to_user_map = map_user_id_to_user(rocketchat_data["user"])

        self.assert_length(rocketchat_data["user"], 6)
        self.assert_length(user_id_to_user_map, 6)

        self.assertEqual(
            user_id_to_user_map[rocketchat_data["user"][0]["_id"]], rocketchat_data["user"][0]
        )

    def test_map_username_to_user_id(self) -> None:
        fixture_dir_name = self.fixture_file_name("", "rocketchat_fixtures")
        rocketchat_data = rocketchat_data_to_dict(fixture_dir_name)

        user_id_to_user_map = map_user_id_to_user(rocketchat_data["user"])
        username_to_user_id_map = map_username_to_user_id(user_id_to_user_map)

        self.assert_length(rocketchat_data["user"], 6)
        self.assert_length(username_to_user_id_map, 6)

        self.assertEqual(
            username_to_user_id_map[rocketchat_data["user"][0]["username"]],
            rocketchat_data["user"][0]["_id"],
        )

    def test_process_users(self) -> None:
        fixture_dir_name = self.fixture_file_name("", "rocketchat_fixtures")
        rocketchat_data = rocketchat_data_to_dict(fixture_dir_name)

        user_id_to_user_map = map_user_id_to_user(rocketchat_data["user"])

        realm_id = 3
        domain_name = "zulip.com"

        user_handler = UserHandler()
        user_id_mapper = IdMapper[str]()

        process_users(
            user_id_to_user_map=user_id_to_user_map,
            realm_id=realm_id,
            domain_name=domain_name,
            user_handler=user_handler,
            user_id_mapper=user_id_mapper,
        )

        self.assert_length(user_handler.get_all_users(), 6)
        self.assertTrue(user_id_mapper.has(rocketchat_data["user"][0]["_id"]))
        self.assertTrue(user_id_mapper.has(rocketchat_data["user"][4]["_id"]))

        user_id = user_id_mapper.get(rocketchat_data["user"][0]["_id"])
        user = user_handler.get_user(user_id)

        self.assertEqual(user["full_name"], rocketchat_data["user"][0]["name"])
        self.assertEqual(user["avatar_source"], "G")
        self.assertEqual(user["delivery_email"], "rocket.cat-bot@zulip.com")
        self.assertEqual(user["email"], "rocket.cat-bot@zulip.com")
        self.assertEqual(user["full_name"], "Rocket.Cat")
        self.assertEqual(user["id"], 1)
        self.assertEqual(user["is_active"], False)
        self.assertEqual(user["is_mirror_dummy"], False)
        self.assertEqual(user["is_bot"], True)
        self.assertEqual(user["bot_type"], 1)
        self.assertEqual(user["bot_owner"], 2)
        self.assertEqual(user["role"], UserProfile.ROLE_MEMBER)
        self.assertEqual(user["realm"], realm_id)
        self.assertEqual(user["short_name"], "rocket.cat")
        self.assertEqual(user["timezone"], "UTC")
        self.assertEqual(user["is_imported_stub"], True)

        user_id = user_id_mapper.get(rocketchat_data["user"][2]["_id"])
        user = user_handler.get_user(user_id)

        self.assertEqual(user["full_name"], rocketchat_data["user"][2]["name"])
        self.assertEqual(user["avatar_source"], "G")
        self.assertEqual(user["delivery_email"], "harrypotter@email.com")
        self.assertEqual(user["email"], "harrypotter@email.com")
        self.assertEqual(user["full_name"], "Harry Potter")
        self.assertEqual(user["id"], 3)
        self.assertEqual(user["is_active"], True)
        self.assertEqual(user["is_mirror_dummy"], False)
        self.assertEqual(user["is_bot"], False)
        self.assertEqual(user["bot_type"], None)
        self.assertEqual(user["bot_owner"], None)
        self.assertEqual(user["role"], UserProfile.ROLE_REALM_OWNER)
        self.assertEqual(user["realm"], realm_id)
        self.assertEqual(user["short_name"], "harry.potter")
        self.assertEqual(user["timezone"], "UTC")
        self.assertEqual(user["is_imported_stub"], True)

        # Test `is_mirror_dummy` set for users of type `unknown`
        rocketchat_data["user"].append(
            {
                "_id": "s0m34ndmID",
                "createdAt": datetime(2019, 11, 6, 0, 38, 42, 796000, tzinfo=timezone.utc),
                "type": "unknown",
                "roles": ["unknown"],
                "name": "Unknown user",
                "username": "unknown",
            }
        )
        user_id_to_user_map = map_user_id_to_user(rocketchat_data["user"])

        process_users(
            user_id_to_user_map=user_id_to_user_map,
            realm_id=realm_id,
            domain_name=domain_name,
            user_handler=user_handler,
            user_id_mapper=user_id_mapper,
        )

        self.assert_length(user_handler.get_all_users(), 7)
        self.assertTrue(user_id_mapper.has(rocketchat_data["user"][6]["_id"]))

        user_id = user_id_mapper.get(rocketchat_data["user"][6]["_id"])
        user = user_handler.get_user(user_id)

        self.assertEqual(user["id"], 7)
        self.assertEqual(user["is_active"], False)
        self.assertEqual(user["is_mirror_dummy"], True)
        self.assertEqual(user["is_bot"], False)

        # Importer should raise error when user emails are malformed
        bad_email1 = rocketchat_data["user"][0]["emails"][0]["address"] = "test1@hotmai,l.om"
        bad_email2 = rocketchat_data["user"][1]["emails"][0]["address"] = "test2@gmail.c"
        user_id_to_user_map = map_user_id_to_user(rocketchat_data["user"])
        with self.assertRaises(Exception) as e:
            process_users(
                user_id_to_user_map=user_id_to_user_map,
                realm_id=realm_id,
                domain_name=domain_name,
                user_handler=user_handler,
                user_id_mapper=user_id_mapper,
            )
        error_message = str(e.exception)
        expected_error_message = f"['Invalid email format, please fix the following email(s) and try again: {bad_email1}, {bad_email2}']"
        self.assertEqual(error_message, expected_error_message)

    def test_categorize_channels_and_map_with_id(self) -> None:
        fixture_dir_name = self.fixture_file_name("", "rocketchat_fixtures")
        rocketchat_data = rocketchat_data_to_dict(fixture_dir_name)

        room_id_to_room_map: dict[str, dict[str, Any]] = {}
        team_id_to_team_map: dict[str, dict[str, Any]] = {}
        dsc_id_to_dsc_map: dict[str, dict[str, Any]] = {}
        direct_id_to_direct_map: dict[str, dict[str, Any]] = {}
        direct_message_group_id_to_direct_message_group_map: dict[str, dict[str, Any]] = {}
        livechat_id_to_livechat_map: dict[str, dict[str, Any]] = {}

        with self.assertLogs(level="INFO"):
            categorize_channels_and_map_with_id(
                channel_data=rocketchat_data["room"],
                room_id_to_room_map=room_id_to_room_map,
                team_id_to_team_map=team_id_to_team_map,
                dsc_id_to_dsc_map=dsc_id_to_dsc_map,
                direct_id_to_direct_map=direct_id_to_direct_map,
                direct_message_group_id_to_direct_message_group_map=direct_message_group_id_to_direct_message_group_map,
                livechat_id_to_livechat_map=livechat_id_to_livechat_map,
            )

        self.assert_length(rocketchat_data["room"], 16)
        # Teams are a subset of rooms.
        self.assert_length(room_id_to_room_map, 6)
        self.assert_length(team_id_to_team_map, 1)
        self.assert_length(dsc_id_to_dsc_map, 5)
        self.assert_length(direct_id_to_direct_map, 2)
        self.assert_length(direct_message_group_id_to_direct_message_group_map, 1)
        self.assert_length(livechat_id_to_livechat_map, 2)

        room_id = rocketchat_data["room"][0]["_id"]
        self.assertIn(room_id, room_id_to_room_map)
        self.assertEqual(room_id_to_room_map[room_id], rocketchat_data["room"][0])

        team_id = rocketchat_data["room"][3]["teamId"]
        self.assertIn(team_id, team_id_to_team_map)
        self.assertEqual(team_id_to_team_map[team_id], rocketchat_data["room"][3])

        dsc_id = rocketchat_data["room"][7]["_id"]
        self.assertIn(dsc_id, dsc_id_to_dsc_map)
        self.assertEqual(dsc_id_to_dsc_map[dsc_id], rocketchat_data["room"][7])

        direct_id = rocketchat_data["room"][4]["_id"]
        self.assertIn(direct_id, direct_id_to_direct_map)
        self.assertEqual(direct_id_to_direct_map[direct_id], rocketchat_data["room"][4])

        direct_message_group_id = rocketchat_data["room"][12]["_id"]
        self.assertIn(direct_message_group_id, direct_message_group_id_to_direct_message_group_map)
        self.assertEqual(
            direct_message_group_id_to_direct_message_group_map[direct_message_group_id],
            rocketchat_data["room"][12],
        )

        livechat_id = rocketchat_data["room"][14]["_id"]
        self.assertIn(livechat_id, livechat_id_to_livechat_map)
        self.assertEqual(livechat_id_to_livechat_map[livechat_id], rocketchat_data["room"][14])

    def test_convert_channel_data(self) -> None:
        fixture_dir_name = self.fixture_file_name("", "rocketchat_fixtures")
        rocketchat_data = rocketchat_data_to_dict(fixture_dir_name)

        mock_realm_dict: ZerverFieldsT = dict(zerver_realm=[dict()])
        zerver_realm = mock_realm_dict["zerver_realm"]
        realm_id = 3
        stream_id_mapper = IdMapper[str]()

        room_id_to_room_map: dict[str, dict[str, Any]] = {}
        team_id_to_team_map: dict[str, dict[str, Any]] = {}
        dsc_id_to_dsc_map: dict[str, dict[str, Any]] = {}
        direct_id_to_direct_map: dict[str, dict[str, Any]] = {}
        direct_message_group_id_to_direct_message_group_map: dict[str, dict[str, Any]] = {}
        livechat_id_to_livechat_map: dict[str, dict[str, Any]] = {}

        with self.assertLogs(level="INFO"):
            categorize_channels_and_map_with_id(
                channel_data=rocketchat_data["room"],
                room_id_to_room_map=room_id_to_room_map,
                team_id_to_team_map=team_id_to_team_map,
                dsc_id_to_dsc_map=dsc_id_to_dsc_map,
                direct_id_to_direct_map=direct_id_to_direct_map,
                direct_message_group_id_to_direct_message_group_map=direct_message_group_id_to_direct_message_group_map,
                livechat_id_to_livechat_map=livechat_id_to_livechat_map,
            )

        zerver_stream = convert_channel_data(
            realm=mock_realm_dict,
            room_id_to_room_map=room_id_to_room_map,
            team_id_to_team_map=team_id_to_team_map,
            stream_id_mapper=stream_id_mapper,
            realm_id=realm_id,
        )

        # Only rooms are converted to streams.
        self.assert_length(room_id_to_room_map, 6)
        self.assert_length(zerver_stream, 6)

        # Normal public stream
        self.assertEqual(zerver_stream[0]["name"], "general")
        self.assertEqual(zerver_stream[0]["invite_only"], False)
        self.assertEqual(zerver_stream[0]["description"], "This is a general channel.")
        self.assertEqual(zerver_stream[0]["rendered_description"], "")
        self.assertEqual(zerver_stream[0]["stream_post_policy"], 1)
        self.assertEqual(zerver_stream[0]["realm"], realm_id)

        self.assertEqual(
            zerver_realm[0]["zulip_update_announcements_stream"], zerver_stream[0]["id"]
        )
        self.assertEqual(zerver_realm[0]["new_stream_announcements_stream"], zerver_stream[0]["id"])

        # Private stream
        self.assertEqual(zerver_stream[1]["name"], "random")
        self.assertEqual(zerver_stream[1]["invite_only"], True)
        self.assertEqual(zerver_stream[1]["description"], "")
        self.assertEqual(zerver_stream[1]["rendered_description"], "")
        self.assertEqual(zerver_stream[1]["stream_post_policy"], 1)
        self.assertEqual(zerver_stream[1]["realm"], realm_id)

        # Team main
        self.assertEqual(zerver_stream[3]["name"], "[TEAM] team-harry-potter")
        self.assertEqual(zerver_stream[3]["invite_only"], True)
        self.assertEqual(
            zerver_stream[3]["description"], "Welcome to the official Harry Potter team."
        )
        self.assertEqual(zerver_stream[3]["rendered_description"], "")
        self.assertEqual(zerver_stream[3]["stream_post_policy"], 1)
        self.assertEqual(zerver_stream[3]["realm"], realm_id)

        # Team channel
        self.assertEqual(zerver_stream[5]["name"], "thp-channel-2")
        self.assertEqual(zerver_stream[5]["invite_only"], False)
        self.assertEqual(zerver_stream[5]["description"], "[Team team-harry-potter channel]. ")
        self.assertEqual(zerver_stream[5]["rendered_description"], "")
        self.assertEqual(zerver_stream[5]["stream_post_policy"], 1)
        self.assertEqual(zerver_stream[5]["realm"], realm_id)

    def test_convert_stream_subscription_data(self) -> None:
        fixture_dir_name = self.fixture_file_name("", "rocketchat_fixtures")
        rocketchat_data = rocketchat_data_to_dict(fixture_dir_name)

        mock_realm_dict: ZerverFieldsT = dict(zerver_realm=[dict()])
        realm_id = 3
        domain_name = "zulip.com"

        user_handler = UserHandler()
        subscriber_handler = SubscriberHandler()
        user_id_mapper = IdMapper[str]()
        stream_id_mapper = IdMapper[str]()

        user_id_to_user_map = map_user_id_to_user(rocketchat_data["user"])

        process_users(
            user_id_to_user_map=user_id_to_user_map,
            realm_id=realm_id,
            domain_name=domain_name,
            user_handler=user_handler,
            user_id_mapper=user_id_mapper,
        )

        room_id_to_room_map: dict[str, dict[str, Any]] = {}
        team_id_to_team_map: dict[str, dict[str, Any]] = {}
        dsc_id_to_dsc_map: dict[str, dict[str, Any]] = {}
        direct_id_to_direct_map: dict[str, dict[str, Any]] = {}
        direct_message_group_id_to_direct_message_group_map: dict[str, dict[str, Any]] = {}
        livechat_id_to_livechat_map: dict[str, dict[str, Any]] = {}

        with self.assertLogs(level="INFO"):
            categorize_channels_and_map_with_id(
                channel_data=rocketchat_data["room"],
                room_id_to_room_map=room_id_to_room_map,
                team_id_to_team_map=team_id_to_team_map,
                dsc_id_to_dsc_map=dsc_id_to_dsc_map,
                direct_id_to_direct_map=direct_id_to_direct_map,
                direct_message_group_id_to_direct_message_group_map=direct_message_group_id_to_direct_message_group_map,
                livechat_id_to_livechat_map=livechat_id_to_livechat_map,
            )

        zerver_stream = convert_channel_data(
            realm=mock_realm_dict,
            room_id_to_room_map=room_id_to_room_map,
            team_id_to_team_map=team_id_to_team_map,
            stream_id_mapper=stream_id_mapper,
            realm_id=realm_id,
        )

        convert_stream_subscription_data(
            user_id_to_user_map=user_id_to_user_map,
            dsc_id_to_dsc_map=dsc_id_to_dsc_map,
            zerver_stream=zerver_stream,
            stream_id_mapper=stream_id_mapper,
            user_id_mapper=user_id_mapper,
            subscriber_handler=subscriber_handler,
        )

        priyansh_id = user_id_mapper.get(rocketchat_data["user"][1]["_id"])
        harry_id = user_id_mapper.get(rocketchat_data["user"][2]["_id"])
        hermione_id = user_id_mapper.get(rocketchat_data["user"][3]["_id"])
        ron_id = user_id_mapper.get(rocketchat_data["user"][4]["_id"])
        voldemort_id = user_id_mapper.get(rocketchat_data["user"][5]["_id"])

        self.assertEqual(
            subscriber_handler.get_users(stream_id=zerver_stream[0]["id"]),
            {priyansh_id, harry_id, ron_id, hermione_id, voldemort_id},
        )
        self.assertEqual(
            subscriber_handler.get_users(stream_id=zerver_stream[1]["id"]), {priyansh_id, harry_id}
        )
        self.assertEqual(
            subscriber_handler.get_users(stream_id=zerver_stream[2]["id"]), {harry_id, hermione_id}
        )
        self.assertEqual(
            subscriber_handler.get_users(stream_id=zerver_stream[3]["id"]),
            {harry_id, ron_id, hermione_id},
        )
        self.assertEqual(subscriber_handler.get_users(stream_id=zerver_stream[4]["id"]), {harry_id})
        self.assertEqual(subscriber_handler.get_users(stream_id=zerver_stream[5]["id"]), {harry_id})

        # Add a new channel with no user.
        no_user_channel: dict[str, Any] = {
            "_id": "rand0mID",
            "ts": datetime(2021, 7, 15, 10, 58, 23, 647000, tzinfo=timezone.utc),
            "t": "c",
            "name": "no-user-channel",
        }
        room_id_to_room_map[no_user_channel["_id"]] = no_user_channel

        zerver_stream = convert_channel_data(
            realm=mock_realm_dict,
            room_id_to_room_map=room_id_to_room_map,
            team_id_to_team_map=team_id_to_team_map,
            stream_id_mapper=stream_id_mapper,
            realm_id=realm_id,
        )

        convert_stream_subscription_data(
            user_id_to_user_map=user_id_to_user_map,
            dsc_id_to_dsc_map=dsc_id_to_dsc_map,
            zerver_stream=zerver_stream,
            stream_id_mapper=stream_id_mapper,
            user_id_mapper=user_id_mapper,
            subscriber_handler=subscriber_handler,
        )

        self.assert_length(subscriber_handler.get_users(stream_id=zerver_stream[6]["id"]), 0)
        self.assertFalse(zerver_stream[6]["deactivated"])

    def test_convert_direct_message_group_data(self) -> None:
        fixture_dir_name = self.fixture_file_name("", "rocketchat_fixtures")
        rocketchat_data = rocketchat_data_to_dict(fixture_dir_name)

        realm_id = 3
        domain_name = "zulip.com"

        user_handler = UserHandler()
        subscriber_handler = SubscriberHandler()
        user_id_mapper = IdMapper[str]()
        direct_message_group_id_mapper = IdMapper[str]()

        user_id_to_user_map = map_user_id_to_user(rocketchat_data["user"])

        process_users(
            user_id_to_user_map=user_id_to_user_map,
            realm_id=realm_id,
            domain_name=domain_name,
            user_handler=user_handler,
            user_id_mapper=user_id_mapper,
        )

        room_id_to_room_map: dict[str, dict[str, Any]] = {}
        team_id_to_team_map: dict[str, dict[str, Any]] = {}
        dsc_id_to_dsc_map: dict[str, dict[str, Any]] = {}
        direct_id_to_direct_map: dict[str, dict[str, Any]] = {}
        direct_message_group_id_to_direct_message_group_map: dict[str, dict[str, Any]] = {}
        livechat_id_to_livechat_map: dict[str, dict[str, Any]] = {}

        with self.assertLogs(level="INFO"):
            categorize_channels_and_map_with_id(
                channel_data=rocketchat_data["room"],
                room_id_to_room_map=room_id_to_room_map,
                team_id_to_team_map=team_id_to_team_map,
                dsc_id_to_dsc_map=dsc_id_to_dsc_map,
                direct_id_to_direct_map=direct_id_to_direct_map,
                direct_message_group_id_to_direct_message_group_map=direct_message_group_id_to_direct_message_group_map,
                livechat_id_to_livechat_map=livechat_id_to_livechat_map,
            )

        zerver_direct_message_group = convert_direct_message_group_data(
            direct_message_group_id_to_direct_message_group_map=direct_message_group_id_to_direct_message_group_map,
            direct_message_group_id_mapper=direct_message_group_id_mapper,
            user_id_mapper=user_id_mapper,
            subscriber_handler=subscriber_handler,
        )

        self.assert_length(zerver_direct_message_group, 1)

        rc_direct_message_group_id = rocketchat_data["room"][12]["_id"]
        self.assertTrue(direct_message_group_id_mapper.has(rc_direct_message_group_id))

        direct_message_group_id = direct_message_group_id_mapper.get(rc_direct_message_group_id)
        self.assertEqual(
            subscriber_handler.get_users(direct_message_group_id=direct_message_group_id), {3, 4, 5}
        )

    @override_settings(PREFER_DIRECT_MESSAGE_GROUP=True)
    def test_convert_direct_message_group_data_without_personal_recipient(self) -> None:
        fixture_dir_name = self.fixture_file_name("", "rocketchat_fixtures")
        rocketchat_data = rocketchat_data_to_dict(fixture_dir_name)

        realm_id = 3
        domain_name = "zulip.com"

        user_handler = UserHandler()
        subscriber_handler = SubscriberHandler()
        user_id_mapper = IdMapper[str]()
        direct_message_group_id_mapper = IdMapper[str]()

        user_id_to_user_map = map_user_id_to_user(rocketchat_data["user"])

        process_users(
            user_id_to_user_map=user_id_to_user_map,
            realm_id=realm_id,
            domain_name=domain_name,
            user_handler=user_handler,
            user_id_mapper=user_id_mapper,
        )

        direct_message_group_id_to_direct_message_group_map: dict[str, dict[str, Any]] = {}

        with self.assertLogs(level="INFO"):
            categorize_channels_and_map_with_id(
                channel_data=rocketchat_data["room"],
                room_id_to_room_map={},
                team_id_to_team_map={},
                dsc_id_to_dsc_map={},
                direct_id_to_direct_map={},
                direct_message_group_id_to_direct_message_group_map=direct_message_group_id_to_direct_message_group_map,
                livechat_id_to_livechat_map={},
            )

        zerver_direct_message_group = convert_direct_message_group_data(
            direct_message_group_id_to_direct_message_group_map=direct_message_group_id_to_direct_message_group_map,
            direct_message_group_id_mapper=direct_message_group_id_mapper,
            user_id_mapper=user_id_mapper,
            subscriber_handler=subscriber_handler,
        )

        self.assert_length(zerver_direct_message_group, 2)

        rc_direct_message_group_id = rocketchat_data["room"][4]["_id"]
        self.assertTrue(direct_message_group_id_mapper.has(rc_direct_message_group_id))

        direct_message_group_id = direct_message_group_id_mapper.get(rc_direct_message_group_id)
        self.assertEqual(
            subscriber_handler.get_users(direct_message_group_id=direct_message_group_id), {3, 4}
        )

        rc_direct_message_group_id = rocketchat_data["room"][12]["_id"]
        self.assertTrue(direct_message_group_id_mapper.has(rc_direct_message_group_id))

        direct_message_group_id = direct_message_group_id_mapper.get(rc_direct_message_group_id)
        self.assertEqual(
            subscriber_handler.get_users(direct_message_group_id=direct_message_group_id), {3, 4, 5}
        )

    def test_write_emoticon_data(self) -> None:
        fixture_dir_name = self.fixture_file_name("", "rocketchat_fixtures")
        rocketchat_data = rocketchat_data_to_dict(fixture_dir_name)
        output_dir = self.make_import_output_dir("rocketchat")

        with self.assertLogs(level="INFO"):
            zerver_realmemoji = build_custom_emoji(
                realm_id=3,
                custom_emoji_data=rocketchat_data["custom_emoji"],
                output_dir=output_dir,
            )

        self.assert_length(zerver_realmemoji, 5)
        self.assertEqual(zerver_realmemoji[0]["name"], "tick")
        self.assertEqual(zerver_realmemoji[0]["file_name"], "tick.png")
        self.assertEqual(zerver_realmemoji[0]["realm"], 3)
        self.assertEqual(zerver_realmemoji[0]["deactivated"], False)

        self.assertEqual(zerver_realmemoji[1]["name"], "check")
        self.assertEqual(zerver_realmemoji[1]["file_name"], "tick.png")
        self.assertEqual(zerver_realmemoji[1]["realm"], 3)
        self.assertEqual(zerver_realmemoji[1]["deactivated"], False)

        self.assertEqual(zerver_realmemoji[2]["name"], "zulip")
        self.assertEqual(zerver_realmemoji[2]["file_name"], "zulip.png")
        self.assertEqual(zerver_realmemoji[2]["realm"], 3)
        self.assertEqual(zerver_realmemoji[2]["deactivated"], False)

        records_file = os.path.join(output_dir, "emoji", "records.json")
        with open(records_file, "rb") as f:
            records_json = orjson.loads(f.read())

        self.assertEqual(records_json[0]["name"], "tick")
        self.assertEqual(records_json[0]["file_name"], "tick.png")
        self.assertEqual(records_json[0]["realm_id"], 3)
        self.assertEqual(records_json[1]["name"], "check")
        self.assertEqual(records_json[1]["file_name"], "tick.png")
        self.assertEqual(records_json[1]["realm_id"], 3)
        self.assertTrue(os.path.isfile(os.path.join(output_dir, "emoji", records_json[0]["path"])))

        self.assertEqual(records_json[2]["name"], "zulip")
        self.assertEqual(records_json[2]["file_name"], "zulip.png")
        self.assertEqual(records_json[2]["realm_id"], 3)
        self.assertTrue(os.path.isfile(os.path.join(output_dir, "emoji", records_json[2]["path"])))

    def test_map_receiver_id_to_recipient_id(self) -> None:
        fixture_dir_name = self.fixture_file_name("", "rocketchat_fixtures")
        rocketchat_data = rocketchat_data_to_dict(fixture_dir_name)

        mock_realm_dict: ZerverFieldsT = dict(zerver_realm=[dict()])
        realm_id = 3
        domain_name = "zulip.com"

        user_handler = UserHandler()
        subscriber_handler = SubscriberHandler()
        user_id_mapper = IdMapper[str]()
        stream_id_mapper = IdMapper[str]()
        direct_message_group_id_mapper = IdMapper[str]()

        user_id_to_user_map = map_user_id_to_user(rocketchat_data["user"])

        process_users(
            user_id_to_user_map=user_id_to_user_map,
            realm_id=realm_id,
            domain_name=domain_name,
            user_handler=user_handler,
            user_id_mapper=user_id_mapper,
        )

        room_id_to_room_map: dict[str, dict[str, Any]] = {}
        team_id_to_team_map: dict[str, dict[str, Any]] = {}
        dsc_id_to_dsc_map: dict[str, dict[str, Any]] = {}
        direct_id_to_direct_map: dict[str, dict[str, Any]] = {}
        direct_message_group_id_to_direct_message_group_map: dict[str, dict[str, Any]] = {}
        livechat_id_to_livechat_map: dict[str, dict[str, Any]] = {}

        with self.assertLogs(level="INFO"):
            categorize_channels_and_map_with_id(
                channel_data=rocketchat_data["room"],
                room_id_to_room_map=room_id_to_room_map,
                team_id_to_team_map=team_id_to_team_map,
                dsc_id_to_dsc_map=dsc_id_to_dsc_map,
                direct_id_to_direct_map=direct_id_to_direct_map,
                direct_message_group_id_to_direct_message_group_map=direct_message_group_id_to_direct_message_group_map,
                livechat_id_to_livechat_map=livechat_id_to_livechat_map,
            )

        zerver_stream = convert_channel_data(
            realm=mock_realm_dict,
            room_id_to_room_map=room_id_to_room_map,
            team_id_to_team_map=team_id_to_team_map,
            stream_id_mapper=stream_id_mapper,
            realm_id=realm_id,
        )

        zerver_direct_message_group = convert_direct_message_group_data(
            direct_message_group_id_to_direct_message_group_map=direct_message_group_id_to_direct_message_group_map,
            direct_message_group_id_mapper=direct_message_group_id_mapper,
            user_id_mapper=user_id_mapper,
            subscriber_handler=subscriber_handler,
        )

        all_users = user_handler.get_all_users()

        zerver_recipient = build_recipients(
            zerver_userprofile=all_users,
            zerver_stream=zerver_stream,
            zerver_direct_message_group=zerver_direct_message_group,
        )

        stream_id_to_recipient_id: dict[int, int] = {}
        user_id_to_recipient_id: dict[int, int] = {}
        direct_message_group_id_to_recipient_id: dict[int, int] = {}

        map_receiver_id_to_recipient_id(
            zerver_recipient=zerver_recipient,
            stream_id_to_recipient_id=stream_id_to_recipient_id,
            user_id_to_recipient_id=user_id_to_recipient_id,
            direct_message_group_id_to_recipient_id=direct_message_group_id_to_recipient_id,
        )

        # 6 for streams and 6 for users.
        self.assert_length(zerver_recipient, 13)
        self.assert_length(stream_id_to_recipient_id, 6)
        self.assert_length(user_id_to_recipient_id, 6)
        self.assert_length(direct_message_group_id_to_recipient_id, 1)

        # First user recipients are built, followed by stream recipients in `build_recipients`.
        self.assertEqual(
            user_id_to_recipient_id[zerver_recipient[0]["type_id"]], zerver_recipient[0]["id"]
        )
        self.assertEqual(
            user_id_to_recipient_id[zerver_recipient[1]["type_id"]], zerver_recipient[1]["id"]
        )

        self.assertEqual(
            stream_id_to_recipient_id[zerver_recipient[6]["type_id"]], zerver_recipient[6]["id"]
        )
        self.assertEqual(
            stream_id_to_recipient_id[zerver_recipient[7]["type_id"]], zerver_recipient[7]["id"]
        )

        self.assertEqual(
            direct_message_group_id_to_recipient_id[zerver_recipient[12]["type_id"]],
            zerver_recipient[12]["id"],
        )

    def test_separate_channel_private_and_livechat_messages(self) -> None:
        fixture_dir_name = self.fixture_file_name("", "rocketchat_fixtures")
        rocketchat_data = rocketchat_data_to_dict(fixture_dir_name)

        room_id_to_room_map: dict[str, dict[str, Any]] = {}
        team_id_to_team_map: dict[str, dict[str, Any]] = {}
        dsc_id_to_dsc_map: dict[str, dict[str, Any]] = {}
        direct_id_to_direct_map: dict[str, dict[str, Any]] = {}
        direct_message_group_id_to_direct_message_group_map: dict[str, dict[str, Any]] = {}
        livechat_id_to_livechat_map: dict[str, dict[str, Any]] = {}

        with self.assertLogs(level="INFO"):
            categorize_channels_and_map_with_id(
                channel_data=rocketchat_data["room"],
