import logging
import os
import subprocess

from yoyo import get_backend, read_migrations

from src.config import Configuration
from src.internals.database import database


def run_daemon():
    """Bugs to fix at a later time:"""
    """     - Pages can get stuck with an older version of their """
    """       HTML, even after disabling anything and everything """
    """       related to cache. The only resolution as of now is """
    """       a restart of the entire webserver.                 """

    environment_vars = {
        **os.environ.copy(),
        "FLASK_DEBUG": "development" if Configuration().development_mode else "false",
        "NODE_ENV": "development" if Configuration().development_mode else "production",
        "KEMONO_SITE": Configuration().webserver["site"],
        "ICONS_PREPEND": Configuration().webserver["ui"]["files_url_prepend"]["icons_base_url"],
        "BANNERS_PREPEND": Configuration().webserver["ui"]["files_url_prepend"]["banners_base_url"],
        "THUMBNAILS_PREPEND": Configuration().webserver["ui"]["files_url_prepend"]["thumbnails_base_url"],
        "CREATORS_LOCATION": Configuration().webserver["api"]["creators_location"],
    }

    if Configuration().sentry_dsn:
        import sentry_sdk
        from sentry_sdk.integrations.flask import FlaskIntegration
        from sentry_sdk.integrations.redis import RedisIntegration

        sentry_sdk.utils.MAX_STRING_LENGTH = 2048
        sentry_sdk.serializer.MAX_EVENT_BYTES = 10 ** 7
        sentry_sdk.serializer.MAX_DATABAG_DEPTH = 8
        sentry_sdk.serializer.MAX_DATABAG_BREADTH = 20
        sentry_sdk.init(
            integrations=[FlaskIntegration(), RedisIntegration()],
            dsn=Configuration().sentry_dsn,
            release=os.getenv("GIT_COMMIT_HASH") or "NOT_FOUND",
            max_request_body_size = "always",
            max_value_length = 1024 * 4,
            attach_stacktrace = True,
            max_breadcrumbs = 1000,
            send_default_pii = True,
        )

    """ Install client dependencies. """
    if not os.path.isdir("./client/node_modules"):
        subprocess.run(
            ["npm", "ci", "--also=dev", "--legacy-peer-deps"],
            check=True,
            cwd="client",
            env=environment_vars,
        )

    """ Build or run client development server depending on config. """
    if Configuration().development_mode:
        subprocess.Popen(
            ["npm", "run", "dev"],
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            cwd="client",
            env=environment_vars,
        )
    else:
        subprocess.run(["npm", "run", "build"], check=True, cwd="client", env=environment_vars)

    """ Run `tusd`. """
    if Configuration().filehaus["tus"]["manage"]:
        subprocess.Popen(
            [
                "tusd",
                "-upload-dir=./storage/uploads",
                "--hooks-enabled-events",
                "post-create",
                "-hooks-http",
                "http://127.0.0.1:3343"
                # 'http://127.0.0.1:6942/shares/tus'
            ],
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            env=environment_vars,
        )

    database.init()
    try:
        if Configuration().automatic_migrations:
            """Run migrations."""
            backend = get_backend(
                f"postgresql+psycopg://{Configuration().database["user"]}"
                f":{Configuration().database["password"]}"
                f"@{Configuration().database["host"]}:"
                f"{Configuration().database["port"]}"
                f"/{Configuration().database["database"]}"
            )
            migrations = read_migrations("./db/migrations")
            with backend.lock():
                backend.apply_migrations(backend.to_apply(migrations))
            """ Initialize Pgroonga if needed. """
            with database.pool.getconn() as conn:
                try:
                    with conn.cursor() as db:
                        db.execute("CREATE EXTENSION IF NOT EXISTS pgroonga")
                        db.execute(
                            "CREATE INDEX IF NOT EXISTS pgroonga_posts_concat_idx ON posts USING pgroonga ( (title || ' ' || content) );"
                        )
                        db.execute("CREATE INDEX IF NOT EXISTS pgroonga_dms_idx ON dms USING pgroonga (content)")
                    conn.commit()
                except Exception:
                    logging.exception("Failed to do pgronga migrations")
                database.pool.putconn(conn)
    finally:
        """ "Close" the database pool."""
        database.close_pool()

    args = [
        "uwsgi",
        "--ini",
        "./uwsgi.ini",
        "--processes",
        str(Configuration().webserver["workers"]),
        "--http",
        f"0.0.0.0:{Configuration().webserver['port']}",
    ]

    if (threads := Configuration().webserver["threads"]) > 1:
        args += ["--threads", str(threads)]

    if Configuration().development_mode:
        args += ["--py-autoreload", "1"]

    for k, v in Configuration().webserver["uwsgi_options"].items():
        args.append(f"--{k}")
        if k in ("disable-logging", ):
            continue
        args.append(str(v).lower() if isinstance(v, bool) else str(v))

    logging.info(f"Starting UWSGI server with cmdline: {' '.join(args)}")

    subprocess.run(
        args,
        check=True,
        close_fds=True,
        env=environment_vars,
    )
