from snek.system.service import BaseService
from snek.system.template import whitelist_attributes


class ChannelMessageService(BaseService):
    mapper_name = "channel_message"

    async def maintenance(self):
        async for message in self.find():
            updated_at = message["updated_at"]
            html = message["html"]
            await self.save(message)

            self.mapper.db['channel_message'].upsert(
                {
                    "uid": message["uid"],
                    "updated_at": updated_at,
                },
                ["uid"],
            )
            if html != message["html"]:
                print("Reredefined message", message["uid"])


    async def create(self, channel_uid, user_uid, message, is_final=True):
        model = await self.new()

        model["channel_uid"] = channel_uid
        model["user_uid"] = user_uid
        model["message"] = message
        model["is_final"] = is_final

        context = {}

        record = model.record
        context.update(record)
        user = await self.app.services.user.get(uid=user_uid)
        context.update(
            {
                "user_uid": user["uid"],
                "username": user["username"],
                "user_nick": user["nick"],
                "color": user["color"],
            }
        )
        try:
            template = self.app.jinja2_env.get_template("message.html")
            model["html"] = template.render(**context)
            model["html"] = whitelist_attributes(model["html"])
        except Exception as ex:
            print(ex, flush=True)

        if await super().save(model):
            return model
        raise Exception(f"Failed to create channel message: {model.errors}.")

    async def to_extended_dict(self, message):
        user = await self.services.user.get(uid=message["user_uid"])
        if not user:
            return {}
        return {
            "uid": message["uid"],
            "color": user["color"],
            "user_uid": message["user_uid"],
            "channel_uid": message["channel_uid"],
            "user_nick": user["nick"],
            "message": message["message"],
            "created_at": message["created_at"],
            "html": message["html"],
            "username": user["username"],
        }

    async def save(self, model):
        context = {}
        context.update(model.record)
        user = await self.app.services.user.get(model["user_uid"])
        context.update(
            {
                "user_uid": user["uid"],
                "username": user["username"],
                "user_nick": user["nick"],
                "color": user["color"],
            }
        )
        template = self.app.jinja2_env.get_template("message.html")
        model["html"] = template.render(**context)
        model["html"] = whitelist_attributes(model["html"])
        return await super().save(model)

    async def offset(self, channel_uid, page=0, timestamp=None, page_size=30):
        results = []
        offset = page * page_size
        try:
            if timestamp:
                async for model in self.query(
                    "SELECT * FROM channel_message WHERE channel_uid=:channel_uid AND created_at < :timestamp ORDER BY created_at DESC LIMIT :page_size OFFSET :offset",
                    {
                        "channel_uid": channel_uid,
                        "page_size": page_size,
                        "offset": offset,
                        "timestamp": timestamp,
                    },
                ):
                    results.append(model)
            elif page > 0:
                async for model in self.query(
                    "SELECT * FROM channel_message WHERE channel_uid=:channel_uid WHERE created_at < :timestamp ORDER BY created_at DESC LIMIT :page_size",
                    {
                        "channel_uid": channel_uid,
                        "page_size": page_size,
                        "offset": offset,
                        "timestamp": timestamp,
                    },
                ):
                    results.append(model)
            else:
                async for model in self.query(
                    "SELECT * FROM channel_message WHERE channel_uid=:channel_uid ORDER BY created_at DESC LIMIT :page_size OFFSET :offset",
                    {
                        "channel_uid": channel_uid,
                        "page_size": page_size,
                        "offset": offset,
                    },
                ):
                    results.append(model)

        except:
            pass
        results.sort(key=lambda x: x["created_at"])
        return results
