import subprocess
import threading
import socket
import time


class ClickHouseServer:
    def __init__(self, binary_path, config_path, stdout_file=None, stderr_file=None, shutdown_timeout=10):
        self.binary_path = binary_path
        self.config_path = config_path
        self.pipe = None
        self.stdout_file = stdout_file
        self.stderr_file = stderr_file
        self.shutdown_timeout = shutdown_timeout

    def start(self):
        cmd = [self.binary_path, 'server', '--config', self.config_path]
        out_pipe = None
        err_pipe = None
        if self.stdout_file is not None:
            out_pipe = open(self.stdout_file, 'w')
        if self.stderr_file is not None:
            err_pipe = open(self.stderr_file, 'w')
        self.pipe = subprocess.Popen(cmd, stdout=out_pipe, stderr=err_pipe)

    def wait_for_request(self, port, timeout=1):
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            # is not working
            # s.settimeout(timeout)

            step = 0.01
            for iter in range(int(timeout / step)):
                if s.connect_ex(('localhost', port)) == 0:
                    return
                time.sleep(step)

            s.connect(('localhost', port))
        except socket.error as socketerror:
            print("Error: ", socketerror)
            raise

    def shutdown(self, timeout=10):

        def wait(pipe):
            pipe.wait()

        if self.pipe is not None:
            self.pipe.terminate()
            thread = threading.Thread(target=wait, args=(self.pipe,))
            thread.start()
            thread.join(timeout)
            if thread.isAlive():
                self.pipe.kill()
                thread.join()

            if self.pipe.stdout is not None:
                self.pipe.stdout.close()
            if self.pipe.stderr is not None:
                self.pipe.stderr.close()

    def __enter__(self):
        self.start()
        return self

    def __exit__(self, type, value, traceback):
        self.shutdown(self.shutdown_timeout)