import re
from sys import platform

from invoke import task

# Workaround for homebrew installation of Python (https://bugs.python.org/issue22490)
import os
os.environ.pop("__PYVENV_LAUNCHER__", None)

ROOT = os.path.dirname(os.path.realpath(__file__))
# Account for platform differences:
# - *n*x supports `pty`, but windows does not,
# - the virtual environment dir structure differs between *n*x and windows,
# - *n*x uses "python3", but on windows it was kept "python".
if platform == "win32":
    PLATFORM_ARG = dict(
        env={
            "PYTHONUNBUFFERED": "True"
        }
    )
    VENV_BIN_NAME = "Scripts"
    PYTHON = "python"
else:
    PLATFORM_ARG = dict(pty=True)
    VENV_BIN_NAME = "bin"
    PYTHON = "python3"

VENV_BIN_PATH = os.path.join(".", "pulsevenv", VENV_BIN_NAME, "")


def create_env_file(env_file):
    """Create or update the .env file"""
    with open(env_file, "r") as f:
        env_vars = f.read()
    # update the DATABASE_URL env
    new_db_url = "DATABASE_URL=postgres://postgres@localhost:5432/pulse"
    old_db_url = re.search("DATABASE_URL=.*", env_vars)
    if old_db_url:
        env_vars = env_vars.replace(old_db_url.group(0), new_db_url)
    else:
        env_vars = env_vars + "DATABASE_URL=postgres://postgres@localhost:5432/pulse\n"

    # update the ALLOWED_HOSTS env
    new_hosts = "ALLOWED_HOSTS=*"
    old_hosts = re.search("ALLOWED_HOSTS=.*", env_vars)
    if old_hosts:
        env_vars = env_vars.replace(old_hosts.group(0), new_hosts)
    else:
        env_vars = env_vars + "ALLOWED_HOSTS=*\n"

    # create the new env file
    with open(".env", "w") as f:
        f.write(env_vars)


def create_super_user(ctx):
    preamble = "from django.contrib.auth import get_user_model;User = get_user_model();"
    create = "User.objects.create_superuser('admin', 'admin@mozillafoundation.org', 'admin')"
    manage(ctx, f'shell -c "{preamble} {create}"')
    print("\nCreated superuser `admin` with email `admin@mozillafoundation.org` and password `admin`.")


# Project setup and update
@task(aliases=["new-env"])
def setup(ctx):
    """Automate project's configuration and dependencies installation"""
    with ctx.cd(ROOT):
        if os.path.isfile(".env"):
            print("* Updating your .env")
            create_env_file(".env")
        else:
            print("* Creating a new .env")
            create_env_file("sample.env")
        # create virtualenv
        print("* Creating a Python virtual environment")
        if platform == "win32" and not os.path.isfile(VENV_BIN_PATH + "python.exe"):
            ctx.run(f"{PYTHON} -m venv pulsevenv")
        elif not os.path.isfile(VENV_BIN_PATH + "python3"):
            ctx.run(f"{PYTHON} -m venv pulsevenv")
        print("* Installing pip-tools")
        ctx.run(VENV_BIN_PATH + "pip install pip-tools")
        # install deps
        print("* Installing Python dependencies")
        pip_sync(ctx)
        new_db(ctx)


@task(aliases=["catchup"])
def catch_up(ctx):
    """Install dependencies and apply migrations"""
    print("Installing Python dependencies")
    pip_sync(ctx)
    print("Applying database migrations")
    migrate(ctx)


@task
def new_db(ctx):
    """Create a new database with fake data"""
    print("* Reset the database")
    ctx.run("dropdb --if-exists -h localhost -U postgres pulse")
    ctx.run("createdb -h localhost -U postgres pulse")
    print("* Migrating database")
    migrate(ctx)
    print("* Creating fake data")
    manage(ctx, "load_fake_data")
    create_super_user(ctx)
    print("* Done!\n"
          "You can get a full list of inv commands with 'inv -l'\n"
          "Start you server with 'inv runserver'\n"
          )


# Django shorthands
@task
def manage(ctx, command):
    """Shorthand to manage.py. inv docker-manage \"[COMMAND] [ARG]\""""
    with ctx.cd(ROOT):
        ctx.run(VENV_BIN_PATH + f"python manage.py {command}", **PLATFORM_ARG)


@task
def runserver(ctx, arguments=""):
    """Start a web server"""
    manage(ctx, f"runserver {arguments}")


@task
def migrate(ctx):
    """Updates database schema"""
    manage(ctx, "migrate")


@task
def makemigrations(ctx):
    """Creates new migration(s) for apps"""
    manage(ctx, "makemigrations")


# Tests
@task
def test(ctx):
    """Run tests"""
    print("Running flake8")
    ctx.run(VENV_BIN_PATH + "python -m flake8 pulseapi", **PLATFORM_ARG)
    print("Running tests")
    manage(ctx, "test")


# Pip-tools
@task(aliases=["docker-pip-compile"])
def pip_compile(ctx, command):
    """Shorthand to pip-tools. inv pip-compile \"[COMMAND] [ARG]\""""
    with ctx.cd(ROOT):
        ctx.run(
            VENV_BIN_PATH + f"pip-compile {command}",
            **PLATFORM_ARG,
        )


@task(aliases=["docker-pip-compile-lock"])
def pip_compile_lock(ctx):
    """Lock prod and dev dependencies"""
    with ctx.cd(ROOT):
        ctx.run(
            VENV_BIN_PATH + "pip-compile",
            **PLATFORM_ARG,
        )
        ctx.run(
            VENV_BIN_PATH + "pip-compile dev-requirements.in",
            **PLATFORM_ARG,
        )


@task(aliases=["docker-pip-sync"])
def pip_sync(ctx):
    """Sync your python virtualenv"""
    with ctx.cd(ROOT):
        ctx.run(
            VENV_BIN_PATH + "pip-sync requirements.txt dev-requirements.txt",
            **PLATFORM_ARG,
        )
