import socket

from lcutils import run
from ..websockets import LogToWS


# ---------------------------------------------------------------------------
class SystemProcess:
    name = ''
    port = 0
    cmd_start = 'sudo /sbin/service {name} start'
    cmd_stop = 'sudo /sbin/service {name} stop'
    cmd_restart = 'sudo /sbin/service {name} restart'
    cmd_reload = 'sudo /sbin/service {name} reload'

    def __init__(
        self,
        name=None,
        port=None,
        cmd_start=None,
        cmd_stop=None,
        cmd_restart=None,
        cmd_reload=None,
    ):
        self.name = name or self.name
        self.port = port or self.port
        self.cmd_start = cmd_start or self.cmd_start.format(name=self.name)
        self.cmd_stop = cmd_stop or self.cmd_stop.format(name=self.name)
        self.cmd_restart = cmd_restart or self.cmd_restart.format(name=self.name)
        self.cmd_reload = cmd_reload or self.cmd_reload.format(name=self.name)

        self.ws_server = LogToWS(publish_ws=True, channel='task_status_messages')

    def get_name(self) -> str:
        """Override in subclass to customize name; i.e. for branding purposes."""
        return self.name.title()

    def publish(self, line: str) -> None:
        self.ws_server.publish_line(line=line)

    def start(self) -> None:
        self.publish(line=f'Starting {self.get_name()}')
        run(self.cmd_start, suppress_stderr=True, suppress_stdout=True)
        self.publish(line=f'{self.get_name()} now running')

    def restart(self) -> None:
        self.publish(line=f'Restarting {self.get_name()}')
        run(self.cmd_restart, suppress_stderr=True, suppress_stdout=True)
        self.publish(line=f'{self.get_name()} now running')

    def reload(self) -> None:
        self.publish(line=f'Reloading {self.get_name()}')
        run(self.cmd_reload, suppress_stderr=True, suppress_stdout=True)
        self.publish(line=f'{self.get_name()} now reloaded')

    def is_running(self) -> bool:
        """
        Check if service is running and if not, attempt to start it
        """
        start_attempts = 0
        service_running = False

        while not service_running and start_attempts < 3:
            try:
                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                s.connect(('localhost', self.port))
                start_attempts = 2
                service_running = True
            except Exception:
                self.start()
                start_attempts += 1
            finally:
                s.close()

        return service_running

    def __str__(self) -> str:
        return f'Init script class for {self.get_name()}'


# ---------------------------------------------------------------------------
class WebServerProcess(SystemProcess):
    name = 'nginx'
    port = 443


# ---------------------------------------------------------------------------
class WebSocketServerProcess(SystemProcess):
    name = 'centrifugo'
    port = 10100


# ---------------------------------------------------------------------------
__all__ = (
    'WebServerProcess',
    'WebSocketServerProcess',
)
