def add_metrics_probes(probes, aggregation, column, probe_type, number_top_values=None):
    """
    Add a metric (column statistics, percentile statistics, or advanced column statistics) to probes
    :param probes: the list of existing probes
    :param aggregation: which aggregation is used (e.g., 'MIN', 'MAX', 'P50', 'MODE')
    :param column: the column dataset to use
    :param probe_type: the type of probe ('col_stats', 'percentile_stats', or 'adv_col_stats')
    :param number_top_values: number of top values (only for 'adv_col_stats')

    Usage example:

    .. code-block:: python

        # For adding column statistics
        add_metrics_probes(metrics['probes'], 'MIN', 'purchase_amount', 'col_stats')

        # For adding percentile statistics
        add_metrics_probes(metrics['probes'], 'P50', 'numerical_variable_1', 'percentile_stats')

        # For adding advanced column statistics
        add_metrics_probes(metrics['probes'], 'MODE', 'categorical_variable_1', 'adv_col_stats', 10)

    """

    types_index = next((index for (index, d) in enumerate(probes) if d["type"] == probe_type), None)
    if types_index is not None:
        # Probe already exists, append to its configuration
        probe_config = probes[types_index]['configuration']
        existing_aggregates = probe_config.get('aggregates', [])
        to_append = {'aggregated': aggregation, 'column': column}
        if to_append not in existing_aggregates:
            existing_aggregates.append(to_append)
            probe_config['aggregates'] = existing_aggregates
            if probe_type == 'adv_col_stats':
                probe_config['numberTopValues'] = number_top_values
    else:
        # Probe does not exist, create a new one
        new_probe_config = {'aggregates': [{'aggregated': aggregation, 'column': column}]}
        if probe_type == 'adv_col_stats':
            new_probe_config['numberTopValues'] = number_top_values

        new_probe = {
            'computeOnBuildMode': 'NO',
            'configuration': new_probe_config,
            'enabled': True,
            'meta': {
                'level': 2 if probe_type == 'col_stats' else 4 if probe_type == 'percentile_stats' else 3,
                'name': 'Columns statistics' if probe_type == 'col_stats' else 'Columns percentiles' if probe_type == 'percentile_stats' else 'Most frequent values'
            },
            'type': probe_type
        }
        probes.append(new_probe)
        print(f'{probe_type} probe appended!')


def add_metrics_probes_col_stats(probes, aggregation, column):
    """
    Add a metrics of column statistics to probes
    :param probes: the list of existing probes
    :param aggregation: which aggregation is used
    :param column: the column dataset to use

     Usage example:

    .. code-block:: python

        settings: DSSDatasetSettings = dataset.get_settings()
        metrics: ComputedMetrics = settings.get_raw()['metrics']
        add_metrics_probes_col_stats(metrics['probes'], 'MIN', 'purchase_amount')

    """

    types_index = next((index for (index, d) in enumerate(probes) if d["type"] == 'col_stats'), None)
    if types_index:
        types_value = probes[types_index]
        existing_aggregation = types_value['configuration']['aggregates']
        to_append = {'aggregated': aggregation, 'column': column}
        if to_append not in existing_aggregation:
            existing_aggregation.append(to_append)
    else:
        probes.append({'computeOnBuildMode': 'NO',
                       'configuration': {'aggregates': [{'aggregated': aggregation,
                                                         'column': column}
                                                        ]},
                       'enabled': True,
                       'meta': {'level': 2, 'name': 'Columns statistics'},
                       'type': 'col_stats'})
        print('probes appended!')

        
def add_displayed_state_to_metrics(displayed_state, type_to_add, function_to_add, column=""):
    """
    Add to the metrics used a new one
    :param displayed_state: the previous state
    :param type_to_add: which kind of metrics
    :param function_to_add: function that been used
    :param column: column if any

    Usage example:
    .. code-block:: python

        settings: DSSDatasetSettings = dataset.get_settings()
        metrics: ComputedMetrics = settings.get_raw()['metrics']
        add_displayed_state_to_metrics(metrics['displayedState'], 'col_stats', 'MIN', 'purchase_amount')

    """

    line_to_add = type_to_add + ':' + function_to_add
    if column:
        line_to_add += ':' + column
    if line_to_add not in displayed_state['metrics']:
        displayed_state['metrics'].append(line_to_add)
        

def get_metrics(dataset):
    """
    Compute and return all used metrics (only id) for a particular dataset
    :param dataset: the dataset

    Usage example:
    .. code-block:: python

        last_metrics = dataset.get_last_metric_values()
        metrics = get_metrics(dataset)
        for metric in metrics:
            metric_value = last_metrics.get_metric_by_id(metric)
            if metric_value and metric_value['lastValues']:
                result[metric] = {
                    'initialValue': metric_value['lastValues'][0]['value']
                }
    """
    dataset.compute_metrics()
    last_metrics = dataset.get_last_metric_values().get_raw()
    return_list = list()
    id_metrics = list(map((lambda metric: metric['metric']['id']),
                          filter(lambda metric: metric['displayedAsMetric'], last_metrics['metrics'])))
    return_list.extend(id_metrics)
    return return_list