from nile.api.v1 import (
    aggregators as na,
    extractors as ne,
    filters as nf
)
from yt.wrapper.ypath import ypath_join

from . import edit_processors

DEFAULT_NMAP_EDITS_PATH = '//home/logfeller/logs/nmaps-edits-log/1d'
DEFAULT_NMAP_USER_PATH = '//home/logfeller/logs/nmaps-users-dump-log/1d'
DEFAULT_NMAP_MODERATION_PATH = '//home/logfeller/logs/nmaps-moderation-log/1d'


def make_fielddate(datefield):
    return str(edit_processors.convert_to_utf(datefield)).split(' ')[0]


def make_moderation_tasks(job, date):
    '''
    Filtered nmaps-moderation-log

    result:
    | puid | commit_id | object_category | event_type | fielddate |
    |------+-----------+-----------------+------------+-----------|
    |  ... |       ... |             ... |        ... |       ... |
    '''
    return job.table(
        ypath_join(DEFAULT_NMAP_MODERATION_PATH, date)
    ).filter(
        nf.not_(nf.equals('task_action', b'created'))
    ).project(
        'puid',
        'commit_id',
        'object_category',
        'event_type',
        fielddate=ne.custom(make_fielddate, 'iso_eventtime')
    ).label('moderation_tasks')


def make_nmaps_user_raw(job, date):
    '''
    result
    | puid | moderation_status |
    |------+-------------------|
    |  ... |               ... |
    '''
    return job.table(
        ypath_join(DEFAULT_NMAP_USER_PATH, date)
    ).project(
        'puid',
        'moderation_status'
    ).label('nmaps_user_raw')


def add_paths(job, moderation_tasks_raw, nmaps_user_raw):
    '''
    Add trees for event_type, object_type and add user status (moderator, yandex-moderator, cartographer)

    moderation_tasks_raw:
    | puid | commit_id | object_category | event_type | fielddate |
    |------+-----------+-----------------+------------+-----------|
    |  ... |       ... |             ... |        ... |       ... |

    nmaps_user_raw:
    | puid | moderation_status |
    |------+-------------------|
    |  ... |               ... |

    moderation_tasks:
    | commit_id | fielddate | puid | event_path | object_path |
    |-----------+-----------+------+------------+-------------|
    |       ... |       ... |  ... |        ... |         ... |

    result:
    | commit_id | fielddate | puid | event_path | object_path | status_path |
    |-----------+-----------+------+------------+-------------+-------------|
    |       ... |       ... |  ... |        ... |         ... |         ... |
    '''
    moderation_tasks = moderation_tasks_raw.map(
        edit_processors.add_object_path_mapper
    ).label('create_object_path').map(
        edit_processors.add_event_path_mapper
    ).label('create_event_path')

    return moderation_tasks.join(
        nmaps_user_raw,
        by=('puid'),
        type='inner'
    ).map(
        edit_processors.add_status_path_mapper
    ).label('moderation_with_paths')


def prepare_result_counts(stream):
    '''
    Calculating the result of statistics.
    Stream is aggregated by unique values from commit_id.

    stream
    | fielddate | status_path | event_path | object_path | commit_id | puid |
    |-----------+-------------+------------+-------------+-----------+------|
    |       ... |         ... |        ... |         ... |       ... |  ... |

    result
    | fielddate | status_path | event_path | object_path | count_uniq_commit_id |
    |-----------+-------------+------------+-------------+----------------------|
    |       ... |         ... |        ... |         ... |                  ... |
    '''
    return stream.unique(
        'fielddate',
        'event_path',
        'object_path',
        'status_path',
        'commit_id'
    ).groupby(
        'fielddate',
        'event_path',
        'object_path',
        'status_path'
    ).aggregate(
        count_uniq_commit_id=na.count()
    ).label(
        'aggregate_by_commit_id'
    ).project(
        'fielddate',
        'event_path',
        'object_path',
        'status_path',
        count_uniq_commit_id=ne.custom(
            lambda count_uniq_commit_id: count_uniq_commit_id or 0,
            'count_uniq_commit_id'
        )
    ).label('prepare_result_counts')
