import dataclasses
import logging
import typing

from synapse.config import ConfigError
from synapse.module_api import ModuleApi
from synapse.spam_checker_api import RegistrationBehaviour

@dataclasses.dataclass(frozen=True)
class Config:
    notification_room: str
    admin_user_id: str
    mention_room: bool = False
    mention_user_ids: list[str] | None = None


class RegistrationNotifier:
    def __init__(self, config: dict[str, typing.Any], api: ModuleApi) -> None:
        self._api = api
        self.config = Config(**config)
        if self.config.notification_room is None:
            raise ConfigError("notification_room is required")
        if self.config.admin_user_id is None:
            raise ConfigError("admin_user_id is required")
        self.log = logging.getLogger(__name__)
        self._api.register_spam_checker_callbacks(check_registration_for_spam=self.check_registration_for_spam)

    async def check_registration_for_spam(
            self,
            email_threepid: dict | None,
            username: str | None,
            request_info: typing.Collection[tuple[str, str]],
            auth_provider_id: str | None = None,
    ) -> RegistrationBehaviour:
        self.log.debug("new registration: %s %s %s %s", email_threepid, username, request_info, auth_provider_id)
        email =  "<No email provided>"
        if email_threepid:
            email = email_threepid.get("address", "<No email provided>")
        username = username or "<will be generated later>"
        sources = []
        for src in request_info:
            sources.append(f"{src[1]}: {src[0]}")  # IP: User-Agent
        sources_str = ", ".join(sources)
        message = (
            f"New user registering:\n- Username: {username} (@{username}:{self._api.server_name})"
            f"\n- Email: {email}\n- SSO Provider ID: {auth_provider_id}\n"
            f"- Originating from (ip, user-agent): {sources_str}"
        )
        try:
            event = {
                "room_id": self.config.notification_room,
                "type": "m.room.message",
                "sender": self.config.admin_user_id,
                "content": {
                    "msgtype": "m.text",
                    "body": message,
                    "m.mentions": {}
                }
            }
            if self.config.mention_room:
                event["m.mentions"]["room"] = True
            if self.config.mention_user_ids:
                event["m.mentions"]["user_ids"] = self.config.mention_user_ids
            logging.debug("sending event: %s", event)
            await self._api.create_and_send_event_into_room(event)
            logging.info("new user registered, message sent to log room %s.", event)
        except Exception as e:
            logging.error("failed to send registration log: %s", e, exc_info=True)
        return RegistrationBehaviour.ALLOW
