"""\
Example.

    %(prog)s production.ini

"""

from webtest import TestApp
from contentbase.storage import DBSession

import atexit
import datetime
import json
import logging
import os
import psycopg2
import select
import signal
import socket
import sqlalchemy.exc
import sys
import threading
import time
from urllib.parse import parse_qsl

log = logging.getLogger(__name__)

EPILOG = __doc__
DEFAULT_TIMEOUT = 60
PY2 = sys.version_info[0] == 2

# We need this because of MVCC visibility.
# See slide 9 at http://momjian.us/main/writings/pgsql/mvcc.pdf
# https://devcenter.heroku.com/articles/postgresql-concurrency


def run(testapp, timeout=DEFAULT_TIMEOUT, dry_run=False, control=None, update_status=None):
    assert update_status is not None

    timestamp = datetime.datetime.now().isoformat()
    update_status(
        status='connecting',
        timestamp=timestamp,
        timeout=timeout,
    )
    max_xid = 0
    engine = DBSession.bind  # DBSession.bind is configured by app init
    # noqa http://docs.sqlalchemy.org/en/latest/faq.html#how-do-i-get-at-the-raw-dbapi-connection-when-using-an-engine
    connection = engine.pool.unique_connection()
    try:
        connection.detach()
        conn = connection.connection
        conn.autocommit = True
        sockets = [conn]
        if control is not None:
            sockets.append(control)
        recovery = None
        listening = False
        with conn.cursor() as cursor:
            while True:
                if not listening:
                    # cannot execute LISTEN during recovery
                    cursor.execute("""SELECT pg_is_in_recovery();""")
                    recovery, = cursor.fetchone()
                    if not recovery:
                        # http://initd.org/psycopg/docs/advanced.html#asynchronous-notifications
                        cursor.execute("""LISTEN "contentbase.transaction";""")
                        cursor.execute("""LISTEN "clincoded.transaction";""")  # BBB
                        log.debug("Listener connected")
                        listening = True

                cursor.execute("""SELECT txid_current_snapshot();""")
                snapshot, = cursor.fetchone()
                timestamp = datetime.datetime.now().isoformat()
                update_status(
                    listening=listening,
                    recovery=recovery,
                    snapshot=snapshot,
                    status='indexing',
                    timestamp=timestamp,
                    max_xid=max_xid,
                )

                try:
                    res = testapp.post_json('/index', {
                        'record': True,
                        'dry_run': dry_run,
                        'recovery': recovery,
                    })