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():
    environment_vars = {
        **os.environ.copy(),
        "FLASK_DEBUG": "development" if Configuration().development_mode else "false",
        "NODE_ENV": "development" if Configuration().development_mode else "production",
    }

    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,
        )

    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))
            backend.connection.close()
            del backend
            """ 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,
    )
