from snek.system.service import BaseService
from datetime import datetime 

from snek.system.model import now 

class ChannelService(BaseService):
    mapper_name = "channel"

    async def get(
        self,
        uid=None,
        **kwargs):
        if uid:
            kwargs['uid'] = uid 
            result = await super().get(**kwargs)
            if result:
                return result 
            del kwargs['uid']
            kwargs['name'] = uid 
            result = await super().get(**kwargs)
            if result:
                return result
            kwargs['name'] = '#' + uid 
            result = await super().get(**kwargs)
            if result:
                return result
            return None 
        return await super().get(**kwargs)

    async def create(
        self,
        label,
        created_by_uid,
        description=None,
        tag=None,
        is_private=False,
        is_listed=True,
    ):
        if label[0] != "#" and is_listed:
            label = f"#{label}"
        count = await self.count(deleted_at=None)
        if not tag and not count:
            tag = "public"
        model = await self.new()
        model["label"] = label
        model["description"] = description
        model["tag"] = tag
        model["created_by_uid"] = created_by_uid
        model["is_private"] = is_private
        model["is_listed"] = is_listed
        if await self.save(model):
            return model
        raise Exception(f"Failed to create channel: {model.errors}.")

    async def get_dm(self, user1, user2):
        channel_member = await self.services.channel_member.get_dm(
            user1, user2 
        )
        if channel_member:
            return await self.get(uid=channel_member["channel_uid"])
        channel = await self.create(
            "DM", user1, tag="dm"            
        )
        await self.services.channel_member.create_dm(
            channel["uid"], user1, user2            
        )
        return channel 

    async def get_users(self, channel_uid):
        users = []
        async for channel_member in self.services.channel_member.find(
            channel_uid=channel_uid,
            is_banned=False,
            is_muted=False,
            deleted_at=None,
        ):
            user =  await self.services.user.get(uid=channel_member["user_uid"])
            if user:
                yield user
    async def get_online_users(self, channel_uid):
        users = []
        async for user in self.get_users(channel_uid):
            if not user["last_ping"]:
                continue

            if (datetime.fromisoformat(now()) - datetime.fromisoformat(user["last_ping"])).total_seconds() < 20:
                yield user 

    async def get_for_user(self, user_uid):
        async for channel_member in self.services.channel_member.find(
            user_uid=user_uid,
            is_banned=False,
            deleted_at=None,
        ):
            channel = await self.get(uid=channel_member["channel_uid"])
            yield channel 

    async def ensure_public_channel(self, created_by_uid):
        model = await self.get(is_listed=True, tag="public")
        is_moderator = False
        if not model:
            is_moderator = True
            model = await self.create(
                "public", created_by_uid=created_by_uid, is_listed=True, tag="public"
            )
        await self.app.services.channel_member.create(
            model["uid"],
            created_by_uid,
            is_moderator=is_moderator,
            is_read_only=False,
            is_muted=False,
            is_banned=False,
        )
        return model
