import logging
from functools import partial
from typing import Any, Tuple

from django.http import JsonResponse, HttpResponse

from staff.monitorings.views import (
    databases,
    firewall_rules,
    gap,
    groups,
    oebs,
    mongodb,
    passport,
    proposals,
    taxi,
    workflow,
    robot_oauth,
)


logger = logging.getLogger(__name__)


DEFAULT_JUGGLER_NAMESPACE: str = 'staff'


CHECK_FUNCTIONS = {
    'firewall_rules': partial(firewall_rules.check_fw_rules_impl, [], False),
    'export_changes': workflow.check_export_changes_works_impl,
    'check_workflow_consistency': workflow.check_workflow_status,
    'locked_proposals': proposals.get_locked_proposals,
    'unpushed_proposals': proposals.proposals_not_pushed_to_oebs,
    'proposal_bp_consistency': proposals.get_proposal_bp_changes,
    'dead-proposal_tasks': proposals.dead_proposal_tasks,
    'dead-gap_tasks': gap.dead_gap_tasks,
    'dead_abc_service_update_tasks': groups.dead_abc_service_update_tasks,
    'proposal-unpushed-struct-changes': proposals.unpushed_struct_changes,
    'check-taxi-auth': lambda: taxi.find_failed_taxi_credentials(taxi.check_taxi_credentials()),
    'unblocked_passports': passport.get_unblocked_passports,
    'gaps_without_tickets': gap.get_gaps_without_ticket,
    'mptt_trees_problems': groups.mptt_trees_problems,
    'oebs_rollup': oebs.rollups_with_problems,
    'failed_bp_code_updates': oebs.failed_bp_code_updates,
    'db': lambda: databases.filterout_alive_databases(databases.get_db_statuses()),
    'pg_stale_transactions': databases.get_stale_transactions,
    'dead_tuples': databases.get_dead_tuples_top,
    'robot_oauth': robot_oauth.monitor_check_invalid_robot_oauth_tokens,
    'office_and_organization_inconsistency': {
        'check_func': oebs.office_and_organization_inconsistency,
        'namespace': 'staff.oebs',
    },
    'check_unlinked_leave_balance': {
        'check_func': oebs.get_unlinked_leave_balance,
        'namespace': 'staff.oebs',
    },
    'check_main_assignment_existence': {
        'check_func': oebs.check_main_assignment_existence,
        'namespace': 'staff.oebs',
    },
    'check_celery_queue_size': mongodb.celery_queue_size_exceeds_limit,
}


def check_result_view(_, check_name: str) -> HttpResponse:
    return JsonResponse(get_check_result(check_name)[0])


def get_check_result(check_name: str) -> Tuple[Any, str]:
    check_func, namespace = _get_handler_by_check_name(check_name=check_name)

    try:
        result = check_func()
        logger.info('%s check finished', check_name)
    except Exception as e:
        logger.exception('%s failed: %s', check_name, e)
        result = {'fatal': str(e)}

    return result, namespace


def _get_handler_by_check_name(check_name: str) -> Tuple[callable, str]:
    check_func = CHECK_FUNCTIONS.get(check_name)
    namespace = DEFAULT_JUGGLER_NAMESPACE

    if isinstance(check_func, dict):
        namespace = check_func.get('namespace', DEFAULT_JUGGLER_NAMESPACE)
        check_func = check_func['check_func']

    return check_func, namespace
