from time import sleep
from .common import prepare_for_termination
from subprocess import Popen, TimeoutExpired
from pathlib import Path
import os

stdout_write = print


def get_mtimes(files) -> dict:
    mtimes = {}
    for p in files:
        try:
            mtimes[p] = p.stat().st_mtime
        except FileNotFoundError:
            pass
    return mtimes


def main(remaining_argv):
    if not remaining_argv:
        remaining_argv = ['8000']
    port = remaining_argv[0]

    proc = Popen(['otree', 'devserver_inner'] + remaining_argv)

    root = Path('.')
    files_to_watch = [
        p
        for p in list(root.glob('*.py')) + list(root.glob('*/*.py'))
        if 'migrations' not in str(p)
    ]
    if os.getenv('OTREE_CORE_DEV'):
        # this code causes it to get stuck on proc.wait() for some reason
        files_to_watch.extend(Path('c:/otree/core/otree').glob('**/*.py'))
        files_to_watch.extend(Path('c:/otree/core/otree_startup').glob('**/*.py'))
    mtimes = get_mtimes(files_to_watch)
    try:
        while True:
            exit_code = proc.poll()
            if exit_code is not None:
                return exit_code
            new_mtimes = get_mtimes(files_to_watch)
            changed_file = None
            for f in files_to_watch:
                if f in new_mtimes and f in mtimes and new_mtimes[f] != mtimes[f]:
                    changed_file = f
                    break
            if changed_file:
                stdout_write(changed_file, 'changed, restarting')
                mtimes = new_mtimes
                child_pid = prepare_for_termination(port)
                proc.terminate()
                # for some reason, with Windows + virtualenv,
                # proc is not the actual django process.
                # so proc.terminate() will not free the port.
                os.kill(child_pid, 9)
                proc = Popen(['otree', 'devserver_inner', port, '--is-reload'])
            sleep(1)
    except KeyboardInterrupt:
        # handle KeyboardInterrupt (KBI) so we don't get a traceback to console.
        # The KBI is received first by the subprocess and then by the parent process.
        # Python's usual behavior is to wait until a subprocess exits before propagating the KBI
        # to the parent process.
        # but for some reason in this program, I got console output from the subprocess that seemed to come
        # after the main process exited. so, we wait.
        proc.wait(2)
