from snek.system.service import BaseService
from snek.system.template import sanitize_html
import time

class ChannelMessageService(BaseService):
    mapper_name = "channel_message"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._configured_indexes = False

    async def maintenance(self):
        args = {}
        for message in self.mapper.db["channel_message"].find():
            print(message)
            try:
                message = await self.get(uid=message["uid"])
                updated_at = message["updated_at"]
                message["is_final"] = True
                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"])
                    
            except Exception as ex:
                time.sleep(0.1)
                print(ex, flush=True)
                
                
        while True:
            changed = 0
            async for message in self.find(is_final=False):
                message["is_final"] = True
                await self.save(message)
                changed += 1
            async for message in self.find(is_final=None):
                message["is_final"] = False
                await self.save(message)
                changed += 1
            if not changed:
                break

    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'] = sanitize_html(model['html'])
        except Exception as ex:
            print(ex, flush=True)

        if await super().save(model):
            if not self._configured_indexes:
                if not self.mapper.db["channel_message"].has_index(
                    ["is_final", "user_uid", "channel_uid"]
                ):
                    self.mapper.db["channel_message"].create_index(
                        ["is_final", "user_uid", "channel_uid"], unique=False
                    )
                if not self.mapper.db["channel_message"].has_index(["uid"]):
                    self.mapper.db["channel_message"].create_index(["uid"], unique=True)
                if not self.mapper.db["channel_message"].has_index(["deleted_at"]):
                    self.mapper.db["channel_message"].create_index(
                        ["deleted_at"], unique=False
                    )
            self._configured_indexes = True
            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 {}

        #if not message["html"].startswith("<chat-message"):
            #message = await self.get(uid=message["uid"])
            #await self.save(message)
        
        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'] = sanitize_html(model['html'])
        return await super().save(model)

    async def offset(self, channel_uid, page=0, timestamp=None, page_size=30):
        channel = await self.services.channel.get(uid=channel_uid)
        if not channel:
            return []
        history_start_filter = ""
        if channel["history_start"]:
            history_start_filter = f" AND created_at > '{channel['history_start']}'"
        results = []
        offset = page * page_size
        try:
            if timestamp:
                async for model in self.query(
                    f"SELECT * FROM channel_message WHERE channel_uid=:channel_uid AND created_at < :timestamp {history_start_filter} 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(
                    f"SELECT * FROM channel_message WHERE channel_uid=:channel_uid WHERE created_at < :timestamp {history_start_filter} 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(
                    f"SELECT * FROM channel_message WHERE channel_uid=:channel_uid {history_start_filter} ORDER BY created_at DESC LIMIT :page_size OFFSET :offset",
                    {
                        "channel_uid": channel_uid,
                        "page_size": page_size,
                        "offset": offset,
                    },
                ):
                    results.append(model)

        except Exception as ex:
            print(ex)
        results.sort(key=lambda x: x["created_at"])
        return results
