import asyncio
import aiohttp
import aiohttp.web
import os
import pty
import shlex
import subprocess
import pathlib

commands = {
    'alpine': 'docker run -it alpine /bin/sh',
    'r': 'docker run -v /usr/local/bin:/usr/local/bin -it ubuntu:latest run.sh',
}

class TerminalSession:
    def __init__(self,command):
        self.master, self.slave = pty.openpty()
        self.sockets =[]
        self.history = b''
        self.history_size = 1024*20
        self.process = subprocess.Popen(
            command.split(" "),
            stdin=self.slave,
            stdout=self.slave,
            stderr=self.slave,
            bufsize=0,
            universal_newlines=True
        )

    async def add_websocket(self, ws):
        asyncio.create_task(self.read_output(ws))

    async def read_output(self, ws):
        self.sockets.append(ws)
        if len(self.sockets) > 1 and self.buffer:
            start = 0
            try:
                start = self.history.index(b'\n')
            except ValueError:
                pass 
            await ws.send_bytes(self.history[start:])
            return 
        loop = asyncio.get_event_loop()
        while True:
            try:
                data = await loop.run_in_executor(None, os.read, self.master, 1024)
                if not data:
                    break
                self.history += data
                if len(self.history) > self.history_size:
                    self.history = self.history[:0-self.history_size]
                try:
                    for ws in self.sockets: await ws.send_bytes(data)  # Send raw bytes for ANSI support
                except:
                    self.sockets.remove(ws)
            except Exception:
                print("Terminating process")
                self.process.terminate()
                print("Terminated process")
                for ws in self.sockets:
                    try:
                        await ws.close()
                    except Exception:
                        pass
                break

    async def write_input(self, data):
        try:
            data = data.encode()
        except AttributeError:
            pass
        await asyncio.get_event_loop().run_in_executor(
            None, os.write, self.master, data
        )
