from __future__ import print_function

import json

from yt import yson  # type: ignore

from nile.api.v1 import clusters, local
from nile.api.v1.record import Record  # type: ignore

from maps.wikimap.stat.nmaps_feedback.lib import eval_report
from maps.wikimap.stat.nmaps_feedback.lib.common import DateWindowsConfig

from maps.wikimap.stat.libs.common.lib import geobase_region as gb

gb.init_geodata_from_resource()

nmaps_users = [
    Record(puid="12345", um_login="a-person", moderation_status="common"),  # users
    Record(puid="54321", um_login="robot-robot", moderation_status="robot"),  # yandex

    # yandex
    Record(puid="1", um_login="anyone", moderation_status="cartographer"),
    Record(puid="2", um_login="yndx-someone", moderation_status="yandex-moderator"),

    # users
    Record(puid="3", um_login="whoever", moderation_status="expert"),
    Record(puid="4", um_login="somebody", moderation_status="moderator"),

]

regions_table = [
    Record(region_id="10262", region_tree='\t10000\t10262\t', population="3018854"),
    Record(region_id="10262", region_tree='\t10000\t', population="0"),
]


def print_records(name, records):
    print('%s:' % name)
    for r in records:
        print(r)


class Sources:
    def __init__(self):
        self.labels = [
            'feedback_db',
            'sprav_table',
            'sprav_changes',
            'nmaps_users',
            'fbapi_issues',
            'regions_table',
        ]

        self.sources = {label: [] for label in self.labels}

        self.sources['nmaps_users'] = nmaps_users
        self.sources['regions_table'] = regions_table

    def set_source(self, label, source):
        self.sources[label] = source

    def prepare_sources(self):
        return {label: local.StreamSource(source) for label, source in self.sources.items()}


class Sinks:
    def __init__(self):
        self.labels = [
            'fbapi_data',
            'sprav_data',
            'full_feedback_data',
            'actions_metrics',
            'unresolved_metrics',
            'resolution_metrics',
            'report_metrics',
        ]

        self.sinks = {label: [] for label in self.labels}

    def prepare_sinks(self):
        return {label: local.ListSink(sink) for label, sink in self.sinks.items()}

    def print_sinks(self):
        for label in self.labels:
            print_records(label, sorted(self.sinks[label]))


def test_smoke():
    print('Begin nmaps_feedback report smoke test')

    cluster = clusters.MockCluster()
    job = cluster.job()
    eval_report.make_testable_job(job, DateWindowsConfig('2018-08-01', '2018-08-01', [1], '2018-08-01'))

    feedback_db = [
        Record(
            position=yson.parser.convert.to_yson_type([44.508769, 40.195504]),
            source='infopoints',
            type='road-closure',
            created_at='2018-08-01 00:00:00.000000+03',
            history=json.loads('[]'),
        ),
    ]

    sources = Sources()
    sources.set_source('feedback_db', feedback_db)

    sinks = Sinks()

    job.local_run(sources=sources.prepare_sources(), sinks=sinks.prepare_sinks())

    correct_report = []
    for source in ['\t_total_\t', '\t_total_\tinfopoints\t']:
        for type in ['\t_total_\t', '\t_total_\troad-closure\t']:
            for geo_path in ['\t10000\t10262\t', '\t10000\t']:
                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\t', test_id_path='\t_total_\t',
                    created=1, unresolved=1, max_task_age=1.0, percentile_95_task_age=1.0
                ))

    sinks.print_sinks()
    print_records('correct_report', sorted(correct_report))

    assert sorted(correct_report) == sorted(sinks.sinks['report_metrics'])


def test_need_info_actions():
    print('Begin nmaps_feedback report need-info actions_metrics test')

    cluster = clusters.MockCluster()
    job = cluster.job()
    eval_report.make_testable_job(job, DateWindowsConfig('2018-08-01', '2018-08-01', [1], '2018-08-01'))

    feedback_db = [
        Record(
            position=yson.parser.convert.to_yson_type([44.508769, 40.195504]),
            source='fbapi',
            type='road-closure',
            created_at='2018-08-01 00:00:00.000000+03',
            history=json.loads('''[
                {"operation": "need-info", "modifiedAt": "2018-08-01 16:01:30.442672+03", "modifiedBy": 946771392},
                {"operation": "open", "modifiedAt": "2018-08-02 17:01:30.442672+03", "modifiedBy": 946771392}
            ]'''),
        ),
        Record(
            position=yson.parser.convert.to_yson_type([44.508769, 40.195504]),
            source='fbapi',
            type='road-closure',
            created_at='2018-08-01 00:00:00.000000+03',
            history=json.loads('''[
                {"operation": "need-info", "modifiedAt": "2018-08-01 16:01:30.442672+03", "modifiedBy": 946771392},
                {"operation": "open", "modifiedAt": "2018-08-01 17:01:30.442672+03", "modifiedBy": 946771392}
            ]'''),
        ),
    ]

    sources = Sources()
    sources.set_source('feedback_db', feedback_db)

    sinks = Sinks()

    job.local_run(sources=sources.prepare_sources(), sinks=sinks.prepare_sinks())

    correct_report = []
    for source in ['\t_total_\t', '\t_total_\tfbapi\t']:
        for type in ['\t_total_\t', '\t_total_\troad-closure\t']:
            for geo_path in ['\t10000\t10262\t', '\t10000\t']:
                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type, test_id_path='\t_total_\t',
                    created=2, need_info=2, un_need_info=1
                ))

    sinks.print_sinks()
    print_records('correct_report', sorted(correct_report))

    assert sorted(correct_report) == sorted(sinks.sinks['actions_metrics'])


def test_need_info_unresolved():
    print('Begin nmaps_feedback report need-info unresolved_metrics test')

    cluster = clusters.MockCluster()
    job = cluster.job()
    eval_report.make_testable_job(job, DateWindowsConfig('2018-08-01', '2018-08-01', [1], '2018-08-01'))

    feedback_db = [
        Record(
            position=yson.parser.convert.to_yson_type([44.508769, 40.195504]),
            source='fbapi',
            type='road-closure',
            created_at='2018-08-01 00:00:00.000000+03',
            history=json.loads('''[
                {"operation": "need-info", "modifiedAt": "2018-08-01 16:01:30.442672+03", "modifiedBy": 946771392},
                {"operation": "open", "modifiedAt": "2018-08-02 17:01:30.442672+03", "modifiedBy": 946771392}
            ]'''),
        ),
        Record(
            position=yson.parser.convert.to_yson_type([44.508769, 40.195504]),
            source='fbapi',
            type='road-closure',
            created_at='2018-08-01 00:00:00.000000+03',
            history=json.loads('''[
                {"operation": "need-info", "modifiedAt": "2018-08-01 16:01:30.442672+03", "modifiedBy": 946771392},
                {"operation": "open", "modifiedAt": "2018-08-01 17:01:30.442672+03", "modifiedBy": 946771392}
            ]'''),
        ),
    ]

    sources = Sources()
    sources.set_source('feedback_db', feedback_db)

    sinks = Sinks()

    job.local_run(sources=sources.prepare_sources(), sinks=sinks.prepare_sinks())

    correct_report = []
    for source in ['\t_total_\t', '\t_total_\tfbapi\t']:
        for type in ['\t_total_\t', '\t_total_\troad-closure\t']:
            for geo_path in ['\t10000\t10262\t', '\t10000\t']:
                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type, test_id_path='\t_total_\t',
                    unresolved=2, max_task_age=1.0, percentile_95_task_age=1.0, unresolved_need_info=1
                ))

    sinks.print_sinks()
    print_records('correct_report', sorted(correct_report))

    assert sorted(correct_report) == sorted(sinks.sinks['unresolved_metrics'])


def test_sprav():
    print('Begin nmaps_feedback report sprav test')

    cluster = clusters.MockCluster()
    job = cluster.job()
    eval_report.make_testable_job(
        job,
        DateWindowsConfig('2018-08-01', '2018-08-01', [1], '2018-08-01'),
    )

    default = Record(
        id='00000000-0000-0000-0000-000000000000',
        service='sprav',
        created_at='2018-08-01 00:00:00.000000+03',
        updated_at='2018-08-01 00:00:00.000000+03',
        status=None,
        original_task=json.loads('''
        {
            "form_context_id": "toponym.add_object_to_map",
            "form_id": "toponym",
            "form_point": { "lat": "40.195504", "lon": "44.508769" },
            "metadata": {
                "client_id": "mobile_maps_ios",
                "yandexuid": "1000000000000000001"
            },
            "question_id": "add_object",
            "answer_id": "entrance"
        }
        ''')
    )
    sprav_table = [
        default,
        Record(default, id='00000000-0000-0000-0000-000000000001', status='published'),
        Record(default, id='00000000-0000-0000-0000-000000000002', status='rejected'),
        Record(
            default,
            created_at='2018-07-01T00:00:00.000000+03',
            id='00000000-0000-0000-0000-000000000003',
            status='accepted'
        ),
    ]
    sprav_changes = [
        Record(
            task_id='00000000-0000-0000-0000-000000000001',
            status='published',
            created_at='2018-08-01T12:00:00.000000+03',
        ),
        Record(
            task_id='00000000-0000-0000-0000-000000000002',
            status='rejected',
            created_at='2018-08-01T12:00:00.000000+03',
        )
    ]

    sources = Sources()
    sources.set_source('sprav_table', sprav_table)
    sources.set_source('sprav_changes', sprav_changes)

    sinks = Sinks()

    job.local_run(sources=sources.prepare_sources(), sinks=sinks.prepare_sinks())

    correct_report = []
    for source in [
        '\t_total_\t',
        '\t_total_\tfbapi\t',
        '\t_total_\tfbapi\tsprav\t',
        '\t_total_\tfbapi\tsprav\tmobile_maps_ios\t',
        '\t_total_\tfbapi\tsprav\tmobile_maps_ios\ttoponym\t',
        '\t_total_\tfbapi\tsprav\tmobile_maps_ios\ttoponym\t_no_key_\t',
        '\t_total_\tfbapi\tsprav\tmobile_maps_ios\ttoponym\t_no_key_\ttoponym.add_object_to_map\t',
    ]:
        for type in ['\t_total_\t', '\t_total_\tpoi_entrance\t']:
            for geo_path in ['\t10000\t10262\t', '\t10000\t']:
                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\t', test_id_path='\t_total_\t',
                    created=3, deployed=1,
                    resolved=2, unresolved=1,
                    resolved_accepted=1, resolved_accepted_total=1,
                    resolved_rejected=1, reject_no_reason=1,
                    percentile_85_created_to_resolved=0.5,
                    max_task_age=1.0, percentile_95_task_age=1.0,
                    fbapi_users_created=1, fbapi_users_resolved=1, fbapi_users_accepted=1,
                ))
                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tNone\t', test_id_path='\t_total_\t',
                    resolved=2,
                    resolved_accepted=1, resolved_accepted_total=1,
                    resolved_rejected=1, reject_no_reason=1,
                    percentile_85_created_to_resolved=0.5,
                ))

    sinks.print_sinks()
    print_records('correct_report', sorted(correct_report))

    assert sorted(correct_report) == sorted(sinks.sinks['report_metrics'])


def test_sprav_org_counters():
    print('Begin nmaps_feedback report sprav org counters test')

    cluster = clusters.MockCluster()
    job = cluster.job()
    eval_report.make_testable_job(
        job,
        DateWindowsConfig('2018-08-01', '2018-08-01', [1], '2018-08-01'),
    )

    sprav_organization_add = Record(
        id='00000000-0000-0000-0000-000000000000',
        service='sprav',
        created_at='2018-08-01 00:00:00.000000+03',
        updated_at='2018-08-01 00:00:00.000000+03',
        status=None,
        original_task=json.loads('''
        {
            "form_context_id": "organization.footer",
            "form_id": "organization",
            "form_point": { "lat": "40.195504", "lon": "44.508769" },
            "metadata": {
                "client_id": "mobile_maps_ios",
                "yandexuid": "1000000000000000002"
            },
            "question_id": "add_object",
            "answer_id": "organization"
        }
        ''')
    )
    sprav_organization_edit = Record(
        sprav_organization_add,
        original_task=json.loads('''
        {
            "form_context_id": "organization.footer",
            "form_id": "organization",
            "form_point": { "lat": "40.195504", "lon": "44.508769" },
            "metadata": {
                "client_id": "mobile_maps_ios",
                "yandexuid": "1000000000000000002"
            },
            "question_id": "closed",
            "answer_id": "permanent",
            "object_id": 123456
        }
        ''')
    )
    sprav_table = [
        Record(
            sprav_organization_add,
            id='00000000-0000-0000-0000-000000000004',
            status='published'),
        Record(
            sprav_organization_add,
            id='00000000-0000-0000-0000-000000000005',
            status='rejected'),
        Record(
            sprav_organization_edit,
            id='00000000-0000-0000-0000-000000000006',
            status='published'),
        Record(
            sprav_organization_edit,
            id='00000000-0000-0000-0000-000000000007',
            status='published'),  # same org
    ]

    sources = Sources()
    sources.set_source('sprav_table', sprav_table)

    sinks = Sinks()

    job.local_run(sources=sources.prepare_sources(), sinks=sinks.prepare_sinks())

    correct_report = []
    for geo_path in ['\t10000\t10262\t', '\t10000\t']:
        for source in [
            '\t_total_\t',
            '\t_total_\tfbapi\t',
            '\t_total_\tfbapi\tsprav\t',
            '\t_total_\tfbapi\tsprav\tmobile_maps_ios\t',
            '\t_total_\tfbapi\tsprav\tmobile_maps_ios\torganization\t',
            '\t_total_\tfbapi\tsprav\tmobile_maps_ios\torganization\t_no_key_\t',
            '\t_total_\tfbapi\tsprav\tmobile_maps_ios\torganization\t_no_key_\torganization.footer\t',
        ]:

            correct_report.append(Record(
                window_days=1, fielddate='2018-08-01',
                geo_path=geo_path, source_path=source, type_path='\t_total_\t',
                user_resolved_path='\t_total_\t', test_id_path='\t_total_\t',
                created=4, deployed=3,
                resolved=4,
                resolved_accepted=3, resolved_accepted_total=3,
                resolved_rejected=1, reject_no_reason=1,
                percentile_85_created_to_resolved=0.0,
                fbapi_users_created=1, fbapi_users_resolved=1, fbapi_users_accepted=1,

                organizations_add=1, organizations_edit=1
            ))
            correct_report.append(Record(
                window_days=1, fielddate='2018-08-01',
                geo_path=geo_path, source_path=source, type_path='\t_total_\t',
                user_resolved_path='\t_total_\tNone\t', test_id_path='\t_total_\t',
                resolved=4,
                resolved_accepted=3, resolved_accepted_total=3,
                resolved_rejected=1, reject_no_reason=1,
                percentile_85_created_to_resolved=0.0,

                organizations_add=1, organizations_edit=1
            ))

            correct_report.append(Record(
                window_days=1, fielddate='2018-08-01',
                geo_path=geo_path, source_path=source, type_path='\t_total_\tpoi\t',
                user_resolved_path='\t_total_\t', test_id_path='\t_total_\t',
                created=2, deployed=1,
                resolved=2,
                resolved_accepted=1, resolved_accepted_total=1,
                resolved_rejected=1, reject_no_reason=1,
                percentile_85_created_to_resolved=0.0,
                fbapi_users_created=1, fbapi_users_resolved=1, fbapi_users_accepted=1,

                organizations_add=1,
            ))
            correct_report.append(Record(
                window_days=1, fielddate='2018-08-01',
                geo_path=geo_path, source_path=source, type_path='\t_total_\tpoi\t',
                user_resolved_path='\t_total_\tNone\t', test_id_path='\t_total_\t',
                resolved=2,
                resolved_accepted=1, resolved_accepted_total=1,
                resolved_rejected=1, reject_no_reason=1,
                percentile_85_created_to_resolved=0.0,

                organizations_add=1,
            ))

            correct_report.append(Record(
                window_days=1, fielddate='2018-08-01',
                geo_path=geo_path, source_path=source, type_path='\t_total_\tpoi_status\t',
                user_resolved_path='\t_total_\t', test_id_path='\t_total_\t',
                created=2, deployed=2,
                resolved=2,
                resolved_accepted=2, resolved_accepted_total=2,
                percentile_85_created_to_resolved=0.0,
                fbapi_users_created=1, fbapi_users_resolved=1, fbapi_users_accepted=1,

                organizations_edit=1
            ))
            correct_report.append(Record(
                window_days=1, fielddate='2018-08-01',
                geo_path=geo_path, source_path=source, type_path='\t_total_\tpoi_status\t',
                user_resolved_path='\t_total_\tNone\t', test_id_path='\t_total_\t',
                resolved=2,
                resolved_accepted=2, resolved_accepted_total=2,
                percentile_85_created_to_resolved=0.0,

                organizations_edit=1
            ))

    sinks.print_sinks()
    print_records('correct_report', sorted(correct_report))

    assert sorted(correct_report) == sorted(sinks.sinks['report_metrics'])


def feedback_db_record(
        id, source=None, created_date='2018-08-01', resolution=None, commit_ids=None, **kwargs):
    return Record(
        id=id,
        position=yson.parser.convert.to_yson_type([44.508769, 40.195504]),
        source='fbapi' if source is None else source,
        type='road',
        created_at=created_date + ' 00:00:00.000000+03',
        history=[],
        resolution=resolution,
        resolved_at=created_date + ' 12:00:00.000000+03' if resolution is not None else None,
        commit_ids=commit_ids if commit_ids is not None else [],
        **kwargs
    )


def fbapi_issues_record(id, yandexuid, created_date='2018-08-01'):
    return Record(
        id=id,
        created_at=created_date + ' 00:00:00.000000+03',
        fbapi_data={
            'original_task': {
                'form_context_id': 'toponym.building',
                'form_id': 'toponym',
                'metadata': {
                    'client_id': 'mobile_maps_ios',
                    'yandexuid': yandexuid
                }
            }
        }
    )


def test_fbapi():
    print('Begin nmaps_feedback report fbapi test')

    cluster = clusters.MockCluster()
    job = cluster.job()
    eval_report.make_testable_job(
        job,
        DateWindowsConfig('2018-08-01', '2018-08-01', [1], '2018-08-01'),
    )

    feedback_db = [
        feedback_db_record(1),
        feedback_db_record(2, resolution='rejected'),
        feedback_db_record(3, resolution='accepted'),
        feedback_db_record(4, resolution='accepted', commit_ids=[1]),
    ]

    fbapi_issues = [
        fbapi_issues_record(1, '1000000000000000001'),
        fbapi_issues_record(2, '1000000000000000002'),
        fbapi_issues_record(3, '1000000000000000003'),
        fbapi_issues_record(4, '1000000000000000004'),
    ]

    sources = Sources()
    sources.set_source('feedback_db', feedback_db)
    sources.set_source('fbapi_issues', fbapi_issues)

    sinks = Sinks()

    job.local_run(sources=sources.prepare_sources(), sinks=sinks.prepare_sinks())

    correct_report = []
    for source in [
        '\t_total_\t',
        '\t_total_\tfbapi\t',
        '\t_total_\tfbapi\ttoponym\t',
        '\t_total_\tfbapi\ttoponym\tmobile_maps_ios\t',
        '\t_total_\tfbapi\ttoponym\tmobile_maps_ios\ttoponym\t',
        '\t_total_\tfbapi\ttoponym\tmobile_maps_ios\ttoponym\t_no_key_\t',
        '\t_total_\tfbapi\ttoponym\tmobile_maps_ios\ttoponym\t_no_key_\ttoponym.building\t',
    ]:
        for type in ['\t_total_\t', '\t_total_\troad\t']:
            for geo_path in ['\t10000\t10262\t', '\t10000\t']:
                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\t', test_id_path='\t_total_\t',
                    created=4, unresolved=1, max_task_age=1.0, percentile_95_task_age=1.0,
                    resolved=3, resolved_accepted=2, resolved_accepted_total=2,
                    resolved_rejected=1, reject_no_reason=1,
                    percentile_85_created_to_resolved=0.5,
                    resolved_with_commit=1, count_unique_resolved_by=1,

                    fbapi_users_created=4,
                    fbapi_users_resolved=3,
                    fbapi_users_accepted=2,
                    fbapi_users_commits=1,
                ))
                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tNone\t', test_id_path='\t_total_\t',
                    resolved=3, resolved_accepted=2, resolved_accepted_total=2,
                    resolved_rejected=1, reject_no_reason=1,
                    percentile_85_created_to_resolved=0.5,
                    resolved_with_commit=1, count_unique_resolved_by=1,
                ))

    sinks.print_sinks()
    print_records('correct_report', sorted(correct_report))

    assert sorted(correct_report) == sorted(sinks.sinks['report_metrics'])


def test_windows():
    print('Begin nmaps_feedback report windows test')

    cluster = clusters.MockCluster()
    job = cluster.job()
    eval_report.make_testable_job(job, DateWindowsConfig('2018-08-01', '2018-08-01', [1, 7, 30], '2018-08-01'))

    feedback_db = [
        feedback_db_record(1),
        feedback_db_record(2, resolution='rejected'),
        feedback_db_record(3, resolution='accepted'),
        feedback_db_record(4, resolution='accepted', commit_ids=[1]),
        feedback_db_record(5, created_date='2018-07-31'),
        feedback_db_record(6, created_date='2018-07-25'),
    ]

    fbapi_issues = [
        fbapi_issues_record(1, '1000000000000000001'),
        fbapi_issues_record(2, '1000000000000000002'),
        fbapi_issues_record(3, '1000000000000000003'),
        fbapi_issues_record(4, '1000000000000000004'),
        fbapi_issues_record(5, '1000000000000000005', created_date='2018-07-31'),
        fbapi_issues_record(6, '1000000000000000005', created_date='2018-07-25'),  # same user, out of 7-day window
    ]

    sources = Sources()
    sources.set_source('feedback_db', feedback_db)
    sources.set_source('fbapi_issues', fbapi_issues)

    sinks = Sinks()

    job.local_run(sources=sources.prepare_sources(), sinks=sinks.prepare_sinks())

    default_record = Record(
        fielddate='2018-08-01',
        user_resolved_path='\t_total_\t', test_id_path='\t_total_\t',
        created=4, unresolved=3, max_task_age=8.0, older_3_days=1,
        percentile_95_task_age=7.3999999999999995,
        resolved=3, resolved_accepted=2, resolved_accepted_total=2,
        resolved_rejected=1, reject_no_reason=1,
        percentile_85_created_to_resolved=0.5,
        resolved_with_commit=1, count_unique_resolved_by=1,

        fbapi_users_created=4,
        fbapi_users_resolved=3,
        fbapi_users_accepted=2,
        fbapi_users_commits=1,
    )
    default_resolved_record = Record(
        fielddate='2018-08-01',
        user_resolved_path='\t_total_\tNone\t', test_id_path='\t_total_\t',
        resolved=3, resolved_accepted=2, resolved_accepted_total=2,
        resolved_rejected=1, reject_no_reason=1,
        percentile_85_created_to_resolved=0.5,
        resolved_with_commit=1, count_unique_resolved_by=1,
    )

    correct_report = []
    for source in [
        '\t_total_\t',
        '\t_total_\tfbapi\t',
        '\t_total_\tfbapi\ttoponym\t',
        '\t_total_\tfbapi\ttoponym\tmobile_maps_ios\t',
        '\t_total_\tfbapi\ttoponym\tmobile_maps_ios\ttoponym\t',
        '\t_total_\tfbapi\ttoponym\tmobile_maps_ios\ttoponym\t_no_key_\t',
        '\t_total_\tfbapi\ttoponym\tmobile_maps_ios\ttoponym\t_no_key_\ttoponym.building\t',
    ]:
        for type in ['\t_total_\t', '\t_total_\troad\t']:
            for geo_path in ['\t10000\t10262\t', '\t10000\t']:
                for window_days in [1, 7, 30]:
                    correct_report.append(Record(
                        default_resolved_record,
                        geo_path=geo_path, source_path=source, type_path=type,

                        window_days=window_days,
                    ))

                correct_report.append(Record(
                    default_record,
                    geo_path=geo_path, source_path=source, type_path=type,

                    window_days=1,
                ))

                correct_report.append(Record(
                    default_record,
                    geo_path=geo_path, source_path=source, type_path=type,

                    window_days=7,
                    created=5,
                    fbapi_users_created=5,
                ))

                correct_report.append(Record(
                    default_record,
                    geo_path=geo_path, source_path=source, type_path=type,

                    window_days=30,
                    created=6,
                    fbapi_users_created=5,
                ))

    sinks.print_sinks()
    print_records('correct_report', sorted(correct_report))

    assert sorted(correct_report) == sorted(sinks.sinks['report_metrics'])


def test_deployed_feedback():
    print('Begin nmaps_feedback report deployed test')

    cluster = clusters.MockCluster()
    job = cluster.job()
    eval_report.make_testable_job(job, DateWindowsConfig('2018-08-01', '2018-08-01', [1], '2018-08-01'))

    feedback_db = [
        Record(
            position=yson.parser.convert.to_yson_type([44.508769, 40.195504]),
            source='infopoints',
            type='road-closure',
            created_at='2018-08-01 00:00:00.000000+03',
            resolved_at='2018-08-01 12:00:00.000000+03', commit_ids=[1234],
            resolved_by=12345,
            resolution='accepted',
            deployed_at='2018-08-01 23:00:00.000000+03',
            history=json.loads('[]'),
        ),
    ]

    sources = Sources()
    sources.set_source('feedback_db', feedback_db)

    sinks = Sinks()

    job.local_run(sources=sources.prepare_sources(), sinks=sinks.prepare_sinks())

    correct_report = []
    for source in ['\t_total_\t', '\t_total_\tinfopoints\t']:
        for type in ['\t_total_\t', '\t_total_\troad-closure\t']:
            for geo_path in ['\t10000\t10262\t', '\t10000\t']:
                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tusers\t', test_id_path='\t_total_\t',
                    resolved=1, resolved_accepted=1, resolved_accepted_total=1, resolved_with_commit=1, count_unique_resolved_by=1,
                    percentile_85_created_to_resolved=0.5,
                ))

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tusers\tcommon\t', test_id_path='\t_total_\t',
                    resolved=1, resolved_accepted=1, resolved_accepted_total=1, resolved_with_commit=1, count_unique_resolved_by=1,
                    percentile_85_created_to_resolved=0.5,
                ))

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\t', test_id_path='\t_total_\t',
                    created=1, deployed=1,
                    resolved=1, resolved_accepted=1, resolved_accepted_total=1, resolved_with_commit=1, count_unique_resolved_by=1,
                    percentile_85_created_to_resolved=0.5,
                ))

    sinks.print_sinks()
    print_records('correct_report', sorted(correct_report))

    assert sorted(correct_report) == sorted(sinks.sinks['report_metrics'])


def test_robot_resolved():
    print('Begin nmaps_feedback report robot test')

    cluster = clusters.MockCluster()
    job = cluster.job()
    eval_report.make_testable_job(job, DateWindowsConfig('2018-08-01', '2018-08-01', [1], '2018-08-01'))

    feedback_db = [
        Record(
            position=yson.parser.convert.to_yson_type([44.508769, 40.195504]),
            source='infopoints',
            type='road-closure',
            created_at='2018-08-01 00:00:00.000000+03',
            resolved_at='2018-08-01 12:00:00.000000+03', commit_ids=[],
            resolved_by=54321,
            resolution='rejected',
            history=json.loads('[]'),
        ),
        Record(
            position=yson.parser.convert.to_yson_type([44.508769, 40.195504]),
            source='infopoints',
            type='road-closure',
            created_at='2018-08-01 00:01:00.000000+03',
            resolved_at='2018-08-01 12:01:00.000000+03', commit_ids=[],
            resolved_by=54321,
            resolution='accepted',
            history=json.loads('[]'),
        ),
    ]

    sources = Sources()
    sources.set_source('feedback_db', feedback_db)

    sinks = Sinks()

    job.local_run(sources=sources.prepare_sources(), sinks=sinks.prepare_sinks())

    correct_report = []
    for source in ['\t_total_\t', '\t_total_\tinfopoints\t']:
        for type in ['\t_total_\t', '\t_total_\troad-closure\t']:
            for geo_path in ['\t10000\t10262\t', '\t10000\t']:
                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\t', test_id_path='\t_total_\t',
                    created=2,
                    resolved=2, resolved_accepted_robot=1, resolved_accepted_total=1,
                    resolved_rejected=1, reject_no_reason=1, count_unique_resolved_by=1,
                    percentile_85_created_to_resolved=0.5,
                ))

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tyandex\t', test_id_path='\t_total_\t',
                    resolved=2, resolved_accepted_robot=1, resolved_accepted_total=1,
                    resolved_rejected=1, reject_no_reason=1, count_unique_resolved_by=1,
                    percentile_85_created_to_resolved=0.5,
                ))

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tyandex\trobot\t', test_id_path='\t_total_\t',
                    resolved=2, resolved_accepted_robot=1, resolved_accepted_total=1,
                    resolved_rejected=1, reject_no_reason=1, count_unique_resolved_by=1,
                    percentile_85_created_to_resolved=0.5,
                ))

    sinks.print_sinks()
    print_records('correct_report', sorted(correct_report))

    assert sorted(correct_report) == sorted(sinks.sinks['report_metrics'])


def test_unresolved_feedback():
    print('Begin nmaps_feedback report unresolved test')

    cluster = clusters.MockCluster()
    job = cluster.job()
    eval_report.make_testable_job(job, DateWindowsConfig('2018-08-01', '2018-08-01', [1], '2018-08-01'))

    feedback_db = [
        Record(
            position=yson.parser.convert.to_yson_type([44.508769, 40.195504]),
            source='infopoints',
            type='road-closure',
            created_at='2018-07-01 00:00:00.000000+03',
            history=json.loads('[]'),
        ),
        Record(
            position=yson.parser.convert.to_yson_type([44.508769, 40.195504]),
            source='infopoints',
            type='road-closure',
            created_at='2018-08-01 00:00:00.000000+03',
            history=json.loads('[]'),
        ),
    ]

    sources = Sources()
    sources.set_source('feedback_db', feedback_db)

    sinks = Sinks()

    job.local_run(sources=sources.prepare_sources(), sinks=sinks.prepare_sinks())

    correct_report = []
    for source in ['\t_total_\t', '\t_total_\tinfopoints\t']:
        for type in ['\t_total_\t', '\t_total_\troad-closure\t']:
            for geo_path in ['\t10000\t10262\t', '\t10000\t']:
                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\t', test_id_path='\t_total_\t',
                    created=1, unresolved=2, max_task_age=32.0, percentile_95_task_age=1.0 + 31.0 * 0.95,
                    older_3_days=1
                ))

    sinks.print_sinks()
    print_records('correct_report', sorted(correct_report))

    assert sorted(correct_report) == sorted(sinks.sinks['report_metrics'])


def test_user_tree():
    print('Begin nmaps_feedback report user tree test')

    cluster = clusters.MockCluster()
    job = cluster.job()
    eval_report.make_testable_job(job, DateWindowsConfig('2018-08-01', '2018-08-01', [1], '2018-08-01'))

    head = Record(
        position=yson.parser.convert.to_yson_type([44.508769, 40.195504]),
        source='infopoints',
        type='road-closure',
        created_at='2018-08-01 00:00:00.000000+03',
        resolved_at='2018-08-01 12:00:00.000000+03',
        resolution='accepted', commit_ids=[],
        history=json.loads('[]'),
    )

    feedback_db = [
        Record(head, resolved_by="12345"),
        Record(head, resolved_by="54321"),
        Record(head, resolved_by="1"),
        Record(head, resolved_by="2"),
        Record(head, resolved_by="3"),
        Record(head, resolved_by="4"),
    ]

    sources = Sources()
    sources.set_source('feedback_db', feedback_db)

    sinks = Sinks()

    job.local_run(sources=sources.prepare_sources(), sinks=sinks.prepare_sinks())

    correct_report = []
    for source in ['\t_total_\t', '\t_total_\tinfopoints\t']:
        for type in ['\t_total_\t', '\t_total_\troad-closure\t']:
            for geo_path in ['\t10000\t10262\t', '\t10000\t']:
                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\t', test_id_path='\t_total_\t',
                    created=6,
                    resolved=6, resolved_accepted=5, resolved_accepted_robot=1,
                    resolved_accepted_total=6, count_unique_resolved_by=6,
                    percentile_85_created_to_resolved=0.5,
                )),

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tusers\t', test_id_path='\t_total_\t',
                    resolved=3, resolved_accepted=3, resolved_accepted_total=3, count_unique_resolved_by=3,
                    percentile_85_created_to_resolved=0.5,
                )),

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tusers\texpert\t', test_id_path='\t_total_\t',
                    resolved=1, resolved_accepted=1, resolved_accepted_total=1, count_unique_resolved_by=1,
                    percentile_85_created_to_resolved=0.5,
                )),

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tusers\texpert\twhoever (3)\t', test_id_path='\t_total_\t',
                    resolved=1, resolved_accepted=1, resolved_accepted_total=1, count_unique_resolved_by=1,
                    percentile_85_created_to_resolved=0.5,
                )),

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tusers\tmoderator\t', test_id_path='\t_total_\t',
                    resolved=1, resolved_accepted=1, resolved_accepted_total=1, count_unique_resolved_by=1,
                    percentile_85_created_to_resolved=0.5,
                )),

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tusers\tmoderator\tsomebody (4)\t', test_id_path='\t_total_\t',
                    resolved=1, resolved_accepted=1, resolved_accepted_total=1, count_unique_resolved_by=1,
                    percentile_85_created_to_resolved=0.5,
                )),

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tusers\tcommon\t', test_id_path='\t_total_\t',
                    resolved=1, resolved_accepted=1, resolved_accepted_total=1, count_unique_resolved_by=1,
                    percentile_85_created_to_resolved=0.5,
                )),

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tyandex\t', test_id_path='\t_total_\t',
                    resolved=3, resolved_accepted=2, resolved_accepted_robot=1, resolved_accepted_total=3, count_unique_resolved_by=3,
                    percentile_85_created_to_resolved=0.5,
                    #                     ^ by human
                )),

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tyandex\tcartographer\t', test_id_path='\t_total_\t',
                    resolved=1, resolved_accepted=1, resolved_accepted_total=1, count_unique_resolved_by=1,
                    percentile_85_created_to_resolved=0.5,
                )),

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tyandex\tcartographer\tanyone (1)\t', test_id_path='\t_total_\t',
                    resolved=1, resolved_accepted=1, resolved_accepted_total=1, count_unique_resolved_by=1,
                    percentile_85_created_to_resolved=0.5,
                )),

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tyandex\trobot\t', test_id_path='\t_total_\t',
                    resolved=1, resolved_accepted_robot=1, resolved_accepted_total=1, count_unique_resolved_by=1,
                    percentile_85_created_to_resolved=0.5,
                    # resolved_accepted=None -- by human
                )),

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tyandex\tyandex-moderator\t', test_id_path='\t_total_\t',
                    resolved=1, resolved_accepted=1, resolved_accepted_total=1, count_unique_resolved_by=1,
                    percentile_85_created_to_resolved=0.5,
                )),

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tyandex\tyandex-moderator\tyndx-someone (2)\t',
                    test_id_path='\t_total_\t',
                    resolved=1, resolved_accepted=1, resolved_accepted_total=1, count_unique_resolved_by=1,
                    percentile_85_created_to_resolved=0.5,
                )),

    sinks.print_sinks()
    print_records('correct_report', sorted(correct_report))

    assert sorted(correct_report) == sorted(sinks.sinks['report_metrics'])


def test_reject_reason():
    print('Begin nmaps_feedback report reject reason test')

    cluster = clusters.MockCluster()
    job = cluster.job()
    eval_report.make_testable_job(job, DateWindowsConfig('2018-08-01', '2018-08-01', [1], '2018-08-01'))

    feedback_db = [
        feedback_db_record(1, source='mrc', resolution='rejected', reject_reason='spam'),
        feedback_db_record(2, source='mrc', resolution='rejected', reject_reason='no-data'),
        feedback_db_record(3, source='mrc', created_date='2018-07-31', resolution='rejected', reject_reason='no-data'),
        feedback_db_record(4, source='mrc', resolution='rejected', reject_reason='redirect-to-sprav'),
        feedback_db_record(5, source='mrc', resolution='rejected', reject_reason='redirect-to-sprav'),
        feedback_db_record(6, source='mrc', resolution='rejected', reject_reason='prohibited-by-rules'),
        feedback_db_record(7, source='mrc', resolution='rejected', reject_reason=''),
        feedback_db_record(8, source='mrc', resolution='rejected'),
        feedback_db_record(9, source='mrc', resolution='accepted'),
        feedback_db_record(10, source='mrc'),
    ]

    sources = Sources()
    sources.set_source('feedback_db', feedback_db)

    sinks = Sinks()

    job.local_run(sources=sources.prepare_sources(), sinks=sinks.prepare_sinks())

    correct_report = []
    for source in ['\t_total_\t', '\t_total_\tmrc\t']:
        for type in ['\t_total_\t', '\t_total_\troad\t']:
            for geo_path in ['\t10000\t10262\t', '\t10000\t']:
                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\t', test_id_path='\t_total_\t',

                    created=9, resolved=8, resolved_accepted=1, resolved_accepted_total=1,
                    resolved_rejected=7, unresolved=1,
                    percentile_85_created_to_resolved=0.5, max_task_age=1.0, percentile_95_task_age=1.0,
                    count_unique_resolved_by=1,

                    reject_no_reason=2,
                    reject_reason_spam=1,
                    reject_reason_no_data=1,
                    reject_reason_redirect_to_sprav=2,
                    reject_reason_prohibited_by_rules=1,
                ))

                correct_report.append(Record(
                    window_days=1, fielddate='2018-08-01',
                    geo_path=geo_path, source_path=source, type_path=type,
                    user_resolved_path='\t_total_\tNone\t', test_id_path='\t_total_\t',

                    resolved=8, resolved_accepted=1, resolved_accepted_total=1,
                    resolved_rejected=7,
                    percentile_85_created_to_resolved=0.5,
                    count_unique_resolved_by=1,

                    reject_no_reason=2,
                    reject_reason_spam=1,
                    reject_reason_no_data=1,
                    reject_reason_redirect_to_sprav=2,
                    reject_reason_prohibited_by_rules=1,
                ))

    sinks.print_sinks()
    print_records('correct_report', sorted(correct_report))

    assert sorted(correct_report) == sorted(sinks.sinks['report_metrics'])
