from snek.system.markdown import strip_markdown
from snek.system.model import now
from snek.system.service import BaseService


class NotificationService(BaseService):
    mapper_name = "notification"

    async def mark_as_read(self, user_uid, channel_message_uid):
        model = await self.get(user_uid, object_uid=channel_message_uid)
        if not model:
            return False
        model["read_at"] = now()
        await self.save(model)
        return True

    async def get_unread_stats(self, user_uid):
        await self.query(
            "SELECT object_type, COUNT(*) as count FROM notification WHERE user_uid=:user_uid AND read_at IS NULL GROUP BY object_type",
            {"user_uid": user_uid},
        )

    async def create(self, object_uid, object_type, user_uid, message):
        model = await self.new()
        model["object_uid"] = object_uid
        model["object_type"] = object_type
        model["user_uid"] = user_uid
        model["message"] = message
        if await self.save(model):
            return model
        raise Exception(f"Failed to create notification: {model.errors}.")

    async def create_channel_message(self, channel_message_uid):
        channel_message = await self.services.channel_message.get(
            uid=channel_message_uid
        )
        if not channel_message["is_final"]:
            return
        user = await self.services.user.get(uid=channel_message["user_uid"])
        self.app.db.begin()
        async for channel_member in self.services.channel_member.find(
            channel_uid=channel_message["channel_uid"],
            is_banned=False,
            is_muted=False,
            deleted_at=None,
        ):
            if not channel_member["new_count"]:
                channel_member["new_count"] = 0
            channel_member["new_count"] += 1

            usr = await self.services.user.get(uid=channel_member["user_uid"])
            if not usr:
                continue
            await self.services.channel_member.save(channel_member)

            model = await self.new()
            model["object_uid"] = channel_message_uid
            model["object_type"] = "channel_message"
            model["user_uid"] = channel_member["user_uid"]
            model["message"] = (
                f"New message from {user['nick']} in {channel_member['label']}."
            )
            try:
                await self.save(model)
            except Exception:
                raise Exception(f"Failed to create notification: {model.errors}.")

            if channel_member["user_uid"] != user["uid"]:
                try:
                    stripped_message = strip_markdown(channel_message["message"])
                    channel_name = await channel_member.get_name()
                    await self.app.services.push.notify_user(
                        user_uid=channel_member["user_uid"],
                        payload={
                            "title": f"New message in {channel_name}",
                            "message": f"{user['nick']}: {stripped_message}",
                            "icon": "/image/snek192.png",
                            "url": f"/channel/{channel_message['channel_uid']}.html",
                        },
                    )
                except Exception as e:
                    print(f"Failed to send push notification:", e)

        self.app.db.commit()
