import logging
from flask_login import current_user

LOG = logging.getLogger(__name__)

def get_dashboard_info(adapter, institute_id=None, slice_query=None):
    """Returns cases with phenotype

        If phenotypes are provided search for only those

    Args:
        adapter(adapter.MongoAdapter)
        institute_id(str): an institute _id
        slice_query(str):  query to filter cases to obtain statistics for.

    Returns:
        data(dict): Dictionary with relevant information
    """

    LOG.debug("General query with institute_id {}.".format(institute_id))

    # if institute_id == 'None' or None, all cases and general stats will be returned
    if institute_id == 'None':
        institute_id = None

    # If a slice_query is present then numbers in "General statistics" and "Case statistics" will
    # reflect the data available for the query
    general_sliced_info = get_general_case_info(adapter, institute_id=institute_id,
                                                    slice_query=slice_query)
    total_sliced_cases = general_sliced_info['total_cases']

    data = {'total_cases': total_sliced_cases}
    if total_sliced_cases == 0:
        return data

    data['pedigree'] = []
    for ped_info in general_sliced_info['pedigree'].values():
        ped_info['percent'] = ped_info['count'] / total_sliced_cases
        data['pedigree'].append(ped_info)

    data['cases'] = get_case_groups(adapter, total_sliced_cases,
                        institute_id=institute_id, slice_query=slice_query)

    data['analysis_types'] = get_analysis_types(adapter, total_sliced_cases,
                                institute_id=institute_id, slice_query=slice_query)

    overview = [
        {
            'title': 'Phenotype terms',
            'count': general_sliced_info['phenotype_cases'],
            'percent': general_sliced_info['phenotype_cases'] / total_sliced_cases,
        },
        {
            'title': 'Causative variants',
            'count': general_sliced_info['causative_cases'],
            'percent': general_sliced_info['causative_cases'] / total_sliced_cases,
        },
        {
            'title': 'Pinned variants',
            'count': general_sliced_info['pinned_cases'],
            'percent': general_sliced_info['pinned_cases'] / total_sliced_cases,
        },
        {
            'title': 'Cohort tag',
            'count': general_sliced_info['cohort_cases'],
            'percent': general_sliced_info['cohort_cases'] / total_sliced_cases,
        }
    ]

    # Data from "Variant statistics tab" is not filtered by slice_query and numbers will
    # reflect verified variants in all available cases for an institute
    general_info = get_general_case_info(adapter, institute_id=institute_id)
    total_cases = general_info['total_cases']
    sliced_case_ids = general_sliced_info['case_ids']
    verified_query = {
        'verb' : 'validate',
    }
    if institute_id: # filter by institute if users wishes so
        verified_query['institute'] =  institute_id

    # Case level information
    sliced_validation_cases = set()
    sliced_validated_cases = set()

    # Variant level information
    validated_tp = set()
    validated_fp = set()
    var_valid_orders = 0 # use this counter to count 'True Positive', 'False positive' and 'Not validated' vars

    validate_events = adapter.event_collection.find(verified_query)
    for validate_event in list(validate_events):
        case_id = validate_event.get('case')
        var_obj = adapter.variant(case_id=case_id, document_id=validate_event['variant_id'])

        if var_obj: # Don't take into account variants which have been removed from db
            var_valid_orders += 1
            if case_id in sliced_case_ids:
                sliced_validation_cases.add(case_id) # add to the set. Can't add same id twice since it'a a set

            validation = var_obj.get('validation')
            if validation and validation in ['True positive', 'False positive']:
                if case_id in sliced_case_ids:
                    sliced_validated_cases.add(case_id)
                if validation == 'True positive':
                    validated_tp.add(var_obj['_id'])
                elif validation == 'False positive':
                    validated_fp.add(var_obj['_id'])

    n_validation_cases = len(sliced_validation_cases)
    n_validated_cases = len(sliced_validated_cases)

    # append
    overview.append(
    {
        'title': 'Validation ordered',
        'count': n_validation_cases,
        'percent': n_validation_cases / total_sliced_cases,
    })
    overview.append(
    {
        'title': 'Validated cases (TP + FP)',
        'count': n_validated_cases,
        'percent': n_validated_cases / total_sliced_cases,
    })

    data['overview'] = overview

    variants = []
    nr_validated = len(validated_tp) + len(validated_fp)
    variants.append(
        {
            'title': 'Validation ordered',
            'count': var_valid_orders,
            'percent': 1
        }
    )

    # taking into account that var_valid_orders might be 0:
    percent_validated_tp = 0
    percent_validated_fp = 0

    if var_valid_orders:
        percent_validated_tp = len(validated_tp) / var_valid_orders
        percent_validated_fp = len(validated_fp) / var_valid_orders

    variants.append(
        {
            'title': 'Validated True Positive',
            'count': len(validated_tp),
            'percent': percent_validated_tp,
        }
    )

    variants.append(
        {
            'title': 'Validated False Positive',
            'count': len(validated_fp),
            'percent': percent_validated_fp,
        }
    )

    data['variants'] = variants
    return data

def get_general_case_info(adapter, institute_id=None, slice_query=None):
    """Return general information about cases

    Args:
        adapter(adapter.MongoAdapter)
        institute_id(str)
        slice_query(str):   Query to filter cases to obtain statistics for.


    Returns:
        general(dict)
    """
    general = {}

    # Potentially sensitive slice queries are assumed allowed if we have got this far
    name_query = slice_query

    cases = adapter.cases(owner=institute_id, name_query=name_query)

    phenotype_cases = 0
    causative_cases = 0
    pinned_cases = 0
    cohort_cases = 0

    pedigree = {
        1: {
            'title': 'Single',
            'count': 0
        },
        2: {
            'title': 'Duo',
            'count': 0
        },
        3: {
            'title': 'Trio',
            'count': 0
        },
        'many': {
            'title': 'Many',
            'count': 0
        },
    }

    case_ids = set()

    total_cases = 0
    for total_cases,case in enumerate(cases,1):
        # If only looking at one institute we need to save the case ids
        if institute_id:
            case_ids.add(case['_id'])
        if case.get('phenotype_terms'):
            phenotype_cases += 1
        if case.get('causatives'):
            causative_cases += 1
        if case.get('suspects'):
            pinned_cases += 1
        if case.get('cohorts'):
            cohort_cases += 1

        nr_individuals = len(case.get('individuals',[]))
        if nr_individuals == 0:
            continue
        if nr_individuals > 3:
            pedigree['many']['count'] += 1
        else:
            pedigree[nr_individuals]['count'] += 1

    general['total_cases'] = total_cases
    general['phenotype_cases'] = phenotype_cases
    general['causative_cases'] = causative_cases
    general['pinned_cases'] = pinned_cases
    general['cohort_cases'] = cohort_cases
    general['pedigree'] = pedigree
    general['case_ids'] = case_ids

    return general


def get_case_groups(adapter, total_cases, institute_id=None, slice_query=None):
    """Return the information about case groups

    Args:
        store(adapter.MongoAdapter)
        total_cases(int): Total number of cases
        slice_query(str): Query to filter cases to obtain statistics for.

    Returns:
        cases(dict):
    """
    # Create a group with all cases in the database
    cases = [{'status': 'all', 'count': total_cases, 'percent': 1}]
    # Group the cases based on their status
    pipeline = []
    group = {'$group' : {'_id': '$status', 'count': {'$sum': 1}}}

    subquery = {}
    if institute_id and slice_query:
        subquery = adapter.cases(owner=institute_id, name_query=slice_query,
                              yield_query=True)
    elif institute_id:
        subquery = adapter.cases(owner=institute_id, yield_query=True)
    elif slice_query:
        subquery = adapter.cases(name_query=slice_query, yield_query=True)

    query = {'$match': subquery} if subquery else {}

    if query:
        pipeline.append(query)

    pipeline.append(group)
    res = adapter.case_collection.aggregate(pipeline)

    for status_group in res:
        cases.append({'status': status_group['_id'],
                      'count': status_group['count'],
                      'percent': status_group['count'] / total_cases})

    return cases

def get_analysis_types(adapter, total_cases, institute_id=None, slice_query=None):
    """ Return information about analysis types.
        Group cases based on analysis type for the individuals.
    Args:
        adapter(adapter.MongoAdapter)
        total_cases(int): Total number of cases
        institute_id(str)
        slice_query(str): Query to filter cases to obtain statistics for.
    Returns:
        analysis_types array of hashes with name: analysis_type(str), count: count(int)

    """
    # Group cases based on analysis type of the individuals
    query = {}

    subquery = {}
    if institute_id and slice_query:
        subquery = adapter.cases(owner=institute_id, name_query=slice_query,
                              yield_query=True)
    elif institute_id:
        subquery = adapter.cases(owner=institute_id, yield_query=True)
    elif slice_query:
        subquery = adapter.cases(name_query=slice_query, yield_query=True)

    query = {'$match': subquery}

    pipeline = []
    if query:
        pipeline.append(query)

    pipeline.append({'$unwind': '$individuals'})
    pipeline.append({'$group': {'_id': '$individuals.analysis_type', 'count': {'$sum': 1}}})
    analysis_query = adapter.case_collection.aggregate(pipeline)
    analysis_types = [{'name': group['_id'], 'count': group['count']} for group in analysis_query]

    return analysis_types
