from maps.wikimap.stat.assessment.report.lib import util

from nile.api.v1 import extractors, filters


def _get_edit_events(date, commit_event_table):
    '''
    commit_event_table:
    | event_id | created_by | created_at | action | bounds_geom | primary_object_category_id | type | ... |
    |----------+------------+------------+--------+-------------+----------------------------+------+-----|
    | ...      | ...        | ...        | ...    | ...         | ...                        | ...  | ... |

    result:
    | event_id | action_by  | action | geom        | category_id                |
    |----------+------------+--------+-------------+----------------------------|
    | ...      | created_by | ...    | bounds_geom | primary_object_category_id |
    '''
    return commit_event_table.filter(
        util.filter_by_date('created_at', date),
        filters.equals('type', b'edit')
    ).project(
        'event_id', 'action',
        action_by=util.extract_as_uint('created_by'),
        geom='bounds_geom',
        category_id='primary_object_category_id'
    )


def _get_non_moderating_events(edit_events, task_active_table, task_closed_table):
    '''
    Leaves events without connected tasks.

    edit_events:
    | event_id | action_by | action | geom | category_id |
    |----------+-----------+--------+------+-------------|
    | ...      | ...       | ...    | ...  | ...         |

    task_active_table, task_closed_table:
    | event_id | ... |
    |----------+-----|
    | ...      | ... |

    result:
    | action_by | action | geom | category_id |
    |-----------+--------+------+-------------|
    | ...       | ...    | ...  | ...         |
    '''
    return edit_events.join(
        task_active_table,
        type='left_only',
        by='event_id'
    ).join(
        task_closed_table,
        type='left_only',
        by='event_id'
    ).project(
        'action_by', 'action', 'geom', 'category_id'
    )


def _get_paid_tasks(date, commit_event_table, task_active_table, task_closed_table):
    '''
    commit_event_table:
    | event_id | created_by | created_at | action | bounds_geom | primary_object_category_id | type | ... |
    |----------+------------+------------+--------+-------------+----------------------------+------+-----|
    | ...      | ...        | ...        | ...    | ...         | ...                        | ...  | ... |

    task_active_table, task_closed_table:
    | event_id | ... |
    |----------+-----|
    | ...      | ... |

    result:
    | action_by  | action | geom        | category_id                |
    |------------+--------+-------------+----------------------------|
    | created_by | ...    | bounds_geom | primary_object_category_id |
    '''
    return _get_non_moderating_events(
        _get_edit_events(date, commit_event_table),
        task_active_table,
        task_closed_table
    )


def _add_task_id(assessed_tasks):
    '''
    assessed_tasks:
    | action_by | action | graded_by | grade | geom | category_id |
    |-----------+--------+-----------+-------+------+-------------|
    | ...       | ...    | ...       | ...   | ...  | ...         |

    result:
    | action_by | action | graded_by | grade | geom | task_id                  |
    |-----------+--------+-----------+-------+------+--------------------------|
    | ...       | ...    | ...       | ...   | ...  | edits/action/category_id |
    '''
    def get_task_id(action, category_id):
        if category_id is None:
            category_id = b'common'

        return b'edits/' + action + b'/' + category_id

    return assessed_tasks.project(
        extractors.all(exclude=['category_id']),
        task_id=extractors.custom(get_task_id, 'action', 'category_id')
    )


def get_tasks(job, date, latest_grades, commit_event_table, task_active_table, task_closed_table):
    '''
    latest_grades:
    | entity_id | action_by | action | graded_by | grade |
    |-----------+-----------+--------+-----------+-------|
    | ...       | ...       | ...    | ...       | ...   |

    commit_event_table:
    | event_id | created_by | created_at | action | bounds_geom | primary_object_category_id | type | ... |
    |----------+------------+------------+--------+-------------+----------------------------+------+-----|
    | ...      | ...        | ...        | ...    | ...         | ...                        | ...  | ... |

    task_active_table, task_closed_table:
    | event_id | ... |
    |----------+-----|
    | ...      | ... |

    result:
    | lat | lon | task_id | action_by | action | graded_by | grade |
    |-----+-----+---------+-----------+--------+-----------+-------|
    | ... | ... | ...     | ...       | ...    | ...       | ...   |
    '''
    tasks = util.concat_assessed_and_paid_tasks(
        job,
        util.get_assessed_tasks(commit_event_table, latest_grades),
        _get_paid_tasks(date, commit_event_table, task_active_table, task_closed_table)
    )
    tasks_with_task_id = _add_task_id(tasks)
    return util.geom_to_lat_lon(tasks_with_task_id)
