"""pgbouncer is a tool for pooling Postgres connections. This is useful because
Postgres can only tolerate a small number of connections, and Django is not very
good at reusing connections for long-lived requests. Using pgbouncer ensures
that we only have a modest number of connections for each Cloud Run instance."""

import configparser
import uuid
from typing import Any, Dict

# This file should NOT import anything Django-related, or we'll get a circular
# import error when we try to import it in settings.py.

PGBOUNCER_ADDRESS = "127.0.0.1"


def write_pgbouncer_config() -> str:
    """Create a pgbouncer config and return a path to it.

    Uses current Postgres settings from default Django database."""
    from django.conf import settings

    db_settings = settings.DATABASES["default"]

    # Assert that the DB backend is postgres
    assert "postgresql" in db_settings["ENGINE"], "Database engine is not Postgres"

    # Generate a unique ID for the auth file
    auth_file_name = f"/tmp/pgb-users-{uuid.uuid4()}.txt"

    # Write to userslist.txt
    with open(auth_file_name, "w") as f:
        f.write(f"\"{db_settings['USER']}\" \"{db_settings['PASSWORD']}\"")

    # Initialize configparser
    config = configparser.ConfigParser()

    # Add databases section
    config["databases"] = {
        db_settings[
            "NAME"
        ]: f"host={db_settings['HOST']} port={db_settings['PORT']} dbname={db_settings['NAME']}"
    }

    # Add pgbouncer section
    config["pgbouncer"] = {
        "listen_addr": PGBOUNCER_ADDRESS,
        "listen_port": str(db_settings["PORT"]),
        "auth_type": "md5",
        "auth_file": auth_file_name,
        "admin_users": db_settings["USER"],
        "pool_mode": "transaction",
        # this is smaller than the default of 20, but will hopefully let us
        # scale to many Cloud Run instances
        "default_pool_size": "10",
        # fast timeout for misbehaved connections
        "server_idle_timeout": "120",
        # be sparse with stats
        "stats_period": "300",
        "log_connections": "0",
        "log_disconnections": "0",
        # default is 300, but we push it up a bit to deal with heavy write
        # loads
        "max_client_conn": "500",
    }

    # Create and write to ini file
    config_file_path = "/tmp/pgbouncer.ini"
    with open(config_file_path, "w") as configfile:
        config.write(configfile)

    return config_file_path


def monkey_patch_pgbouncer_config(database_config: Dict[str, Any]) -> None:
    """Update current settings to use the created pgbouncer."""
    # assert that it's actually postgres
    assert "postgresql" in database_config["ENGINE"], "Database engine is not Postgres"

    # pgbouncer settings
    database_config["HOST"] = PGBOUNCER_ADDRESS
    # see Django docs on transaction pooling:
    # https://docs.djangoproject.com/en/4.2/ref/databases/#transaction-pooling-server-side-cursors
    database_config["DISABLE_SERVER_SIDE_CURSORS"] = True
