from datetime import datetime
import os
from typing import Any, List

from dateutil import parser

from django.conf import settings
from django.db import connection

from staff.emission.django.emission_master.models import NotSent

from staff.monitorings.celery_queue import get_celery_broker_messages_collection

from staff.lib import requests


def _notsent_queue_length() -> int:
    return NotSent.objects.count()


def _notsent_queue_lag() -> float:
    first = NotSent.objects.order_by('entry_id').first()
    if not first:
        return .0

    lag = (datetime.now() - parser.parse(first.entry.creation_time)).total_seconds()
    return lag


def _celery_default_queue_size() -> int:
    messages_collection = get_celery_broker_messages_collection()
    default_q = {'queue': os.getenv('DEPLOY_STAGE_ID', 'celery')}
    default_queue_size = messages_collection.find(default_q).count()
    return default_queue_size


def _celery_trip_queue_size() -> int:
    messages_collection = get_celery_broker_messages_collection()
    trips_q = {'queue': settings.CELERY_TRIPS_QUEUE}
    default_queue_size = messages_collection.find(trips_q).count()
    return default_queue_size


def get_uwsgi_stats_json():
    response = requests.get(url='http://127.0.0.1:1717', timeout=(0.1, 0.5, 5)).json()  # см. uwsgiconf.ini
    return response  # про формат см. https://uwsgi.readthedocs.io/en/latest/StatsServer.html


def _workers_stat():
    # _ammx - брать абсолютные значения, по группе и метагруппе суммировать, при roll-up брать максимальное
    # _axxx - на агенте брать абсолютное значение, по хостам и по времени агрегировать функцией max()
    # см. https://wiki.yandex-team.ru/golovan/userdocs/aggregation-types/
    result = {
        'staff_uwsgi_workers_total_ammx': 0,
        'staff_uwsgi_workers_busy_count_ammx': 0,
        'staff_uwsgi_workers_busy_percent_axxx': 0,
    }
    workers_data = get_uwsgi_stats_json()['workers']
    for worker in workers_data:
        result['staff_uwsgi_workers_total_ammx'] += 1
        result['staff_uwsgi_workers_busy_count_ammx'] += int(worker['status'] == 'busy')

    result['staff_uwsgi_workers_busy_percent_axxx'] = (
            100 * result['staff_uwsgi_workers_busy_count_ammx'] // result['staff_uwsgi_workers_total_ammx']
    )
    return [[key, value] for key, value in result.items()]


def _get_dead_tuples():
    tables = ['whistlah_stafflastoffice', 'person_filter_personsfilter', 'oebs_headcountposition']
    arguments_placeholders = ','.join(['%s'] * len(tables))
    query = f"""
        SELECT relname, n_dead_tup AS "dead_tuples" FROM pg_stat_user_tables
        WHERE schemaname = 'public' AND relname IN ({arguments_placeholders});
    """
    with connection.cursor() as cursor:
        cursor.execute(query, tables)
        return [[f'staff_pg_tables_{row[0]}_deadtuples_axxx', row[1]] for row in cursor.fetchall()]


def get_metrics() -> List[List[Any]]:
    return [
        ['staffapi_not_sent_queue_length_axxx', _notsent_queue_length()],
        ['staffapi_not_sent_queue_lag_axxx', _notsent_queue_lag()],
        ['staff_celery_queue_length_axxx', _celery_default_queue_size()],
        ['staff_trip_queue_length_axxx', _celery_default_queue_size()],
        *_get_dead_tuples(),
    ]


def get_metrics_back() -> List[List[Any]]:
    return [
        *_workers_stat(),
    ]
