from collections import namedtuple
from nile.api.v1 import filters as nf

from . import stream_processors

MAJOR_REGIONS_TABLE = '//home/maps/core/nmaps/analytics/geo-data/major_regions_map'

CategoryFilter = namedtuple('CategoryFilter', ['predicate', 'name'])

ACCESS_TYPES = {
    'pedestrian': 0b000001,
    'bus':        0b000010,
    'truck':      0b000100,
    'auto':       0b001000,
    'bicycle':    0b010000,
    'taxi':       0b100000,
}

# https://a.yandex-team.ru/arc/trunk/arcadia/maps/doc/schemas/ymapsdf/garden/create/ft_poi_attr.sql
POI_POSITION_QUALITY = {
    'precise': 4,
    'user':    5,
}


def rd_el_category_filter(access_type):
    needed_access_id = ACCESS_TYPES[access_type]
    return CategoryFilter(
        predicate=nf.custom(lambda access_id: access_id & needed_access_id, 'access_id'),
        name='rd_el {}'.format(access_type)
    )


def cond_category_filter(cond_type, access_type):
    needed_access_id = ACCESS_TYPES[access_type]
    return CategoryFilter(
        predicate=nf.custom(
            lambda ct, access_id: ct == cond_type and (access_id & needed_access_id),
            'cond_type',
            'access_id'
        ),
        name='cond cond_type={} access_type {}'.format(cond_type, access_type)
    )


def arbats_filter():
    forbidden_access_id = ~(ACCESS_TYPES['pedestrian'] | ACCESS_TYPES['bicycle'])
    return CategoryFilter(
        predicate=nf.custom(
            lambda fc, access_id: fc <= 7 and access_id & forbidden_access_id == 0,
            'fc',
            'access_id'
        ),
        name='rd_el arbats'
    )


ROADS_CATEGORY_FILTERS = [
    CategoryFilter(predicate=None, name='rd_el all'),
    CategoryFilter(
        predicate=nf.custom(lambda fow, oneway: fow not in [1, 2] and oneway != 'B', 'fow', 'oneway'),
        name='rd_el oneway'
    ),
    arbats_filter(),
    CategoryFilter(predicate=nf.equals('paved', 1),                 name='rd_el paved'),
    CategoryFilter(predicate=nf.equals('paved', 0),                 name='rd_el not paved'),
    CategoryFilter(predicate=nf.equals('poor_condition', 1),        name='rd_el poor condition'),
    CategoryFilter(predicate=nf.equals('back_taxi', 1),             name='rd_el back taxi'),
    CategoryFilter(predicate=nf.equals('forward_taxi', 1),          name='rd_el forward taxi'),
    CategoryFilter(predicate=nf.equals('restricted_for_trucks', 1), name='rd_el restricted for trucks'),
    CategoryFilter(predicate=nf.equals('residential', 1),           name='rd_el residential'),
    CategoryFilter(predicate=nf.equals('fow', 14),                  name='rd_el pedestrian zone'),
    CategoryFilter(predicate=nf.equals('struct_type', 1),           name='rd_el struct_type bridge'),
    CategoryFilter(predicate=nf.equals('struct_type', 2),           name='rd_el struct_type tunnel'),
] + [
    rd_el_category_filter(access_type) for access_type in ACCESS_TYPES
]


COND_FILTERS = [
    CategoryFilter(predicate=None, name='cond all'),
] + [
    cond_category_filter(cond_type, access_type)
    # Maneuvers with for these cond_types can have diffirent sets of access types
    # No matter to calculate statistics for other cond_types splitted by access type
    # because result values are equal for all access types
    # (perhaps excluding pedestrian and bicycle for cameras)
    #  1: Prohibited maneuver
    #  3: Allowed maneuver
    #  5: Maneuver permitted by access pass
    for cond_type in [1, 3, 5]
    for access_type in ACCESS_TYPES
] + [
    CategoryFilter(predicate=nf.equals('cond_type', cond_type), name='cond cond_type={}'.format(cond_type))
    for cond_type in range(1, 24)
]


TABLE_CATEGORY_FILTERS = {
    'addr':  [CategoryFilter(predicate=None, name='addr all')],
    'bld':   [CategoryFilter(predicate=None, name='bld all')],
    'cond':  COND_FILTERS,
    'rd_el': ROADS_CATEGORY_FILTERS
}

TABLE_LINEAR_CATEGORY_FILTERS = {
    'rd_el': ROADS_CATEGORY_FILTERS
}

TableProcessor = namedtuple('TableProcessor', ['region_getter', 'preprocessor'])

TABLE_PROCESSORS = {
    'addr':  TableProcessor(stream_processors.add_addr_region, None),
    'cond':  TableProcessor(
        region_getter=stream_processors.add_cond_region,
        preprocessor=stream_processors.remove_autogenerated_conds
    ),
    'bld':   TableProcessor(stream_processors.add_bld_region, None),
    'rd_el': TableProcessor(stream_processors.add_rd_el_region, None),
}


ReportDescriptor = namedtuple(
    'ReportDescriptor',
    ['report_name', 'table_filters', 'preprocess_stream', 'field_to_aggregate', 'available_tables'])


ALL_AVAILABLE_TABLES = TABLE_CATEGORY_FILTERS.keys() + ['ad', 'entrance_flat_range', 'ft', 'ft_ft', 'rd']

COUNT_REPORT_DESCRIPTOR = ReportDescriptor(
    report_name='Maps.Wiki/KPI/AbsoluteValues/ItemsCount',
    table_filters=TABLE_CATEGORY_FILTERS,
    preprocess_stream=stream_processors.set_count_field,
    field_to_aggregate='count',
    available_tables=ALL_AVAILABLE_TABLES,
)
LENGTH_REPORT_DESCRIPTOR = ReportDescriptor(
    report_name='Maps.Wiki/KPI/AbsoluteValues/ItemsLength',
    table_filters=TABLE_LINEAR_CATEGORY_FILTERS,
    preprocess_stream=stream_processors.calc_shape_length,
    field_to_aggregate='length',
    available_tables=TABLE_LINEAR_CATEGORY_FILTERS.keys() + ['rd'],
)
