from snek.system.docker import ComposeFileManager
from snek.system.service import BaseService


class ContainerService(BaseService):
    mapper_name = "container"

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

        self.compose_path = "snek-container-compose.yml"
        self.compose = ComposeFileManager(self.compose_path,self.container_event_handler)
        self.event_listeners = {}

    async def add_event_listener(self, name, event,event_handler):
        if not name in self.event_listeners:
            self.event_listeners[name] = {}
        if not event in self.event_listeners[name]:
            self.event_listeners[name][event] = []
        self.event_listeners[name][event].append(event_handler)

    async def container_event_handler(self, name, event, data):
        event_listeners = self.event_listeners.get(name, {})
        handlers = event_listeners.get(event, [])
        for handler in handlers:
            if not await handler(data):
                handlers.remove(handler)

    async def get_instances(self):
        return list(self.compose.list_instances())

    async def get_container_name(self, channel_uid):
        if channel_uid.startswith("channel-"):
            return channel_uid
        return f"channel-{channel_uid}"

    async def get(self,channel_uid):
        return await self.compose.get_instance(await self.get_container_name(channel_uid))

    async def stop(self, channel_uid):
        return await self.compose.stop(await self.get_container_name(channel_uid))

    async def start(self, channel_uid):
        return await self.compose.start(await self.get_container_name(channel_uid))

    async def maintenance(self):
        async for channel in self.services.channel.find():
            if not await self.get(channel["uid"]):
                print("Creating container for channel", channel["uid"])
                result = await self.create(channel_uid=channel["uid"])
                print(result)


    async def get_status(self, channel_uid):
        return await self.compose.get_instance_status(await self.get_container_name(channel_uid))

    async def write_stdin(self, channel_uid, data):
        return await self.compose.write_stdin(await self.get_container_name(channel_uid), data)

    async def create(
        self,
        channel_uid,
        image="ubuntu:latest",
        command=None,
        cpus=1,
        memory="1024m",
        ports=None,
        volumes=None,
    ):
        name = await self.get_container_name(channel_uid)
            
        test = await self.compose.get_instance(name)
        if test:
            return test

        self.compose.create_instance(
            name,
            image,
            command,
            cpus,
            memory,
            ports,
            [
                "./"
                + str(await self.services.channel.get_home_folder(channel_uid))
                + ":"
                + "/home/ubuntu"
            ],
        )
        return await self.compose.get_instance(name)

    async def create2(
        self, id, name, status, resources=None, user_uid=None, path=None, readonly=False
    ):
        model = await self.new()
        model["id"] = id
        model["name"] = name
        model["status"] = status
        if resources:
            model["resources"] = resources
        if user_uid:
            model["user_uid"] = user_uid
        if path:
            model["path"] = path
        model["readonly"] = readonly
        if await super().save(model):
            return model
        raise Exception(f"Failed to create container: {model.errors}")

