import json
import functools
import datetime


def convertSQLDateTimeToTimestamp(value):
    date, time_ext = value.split(' ')
    if ('+' in time_ext):
        time, tz = time_ext.split('+')
        if (':' in tz):
            tz = '+' + ''.join(tz.split(':'))
    elif ('-' in time_ext):
        time, tz = time_ext.split('-')
        if (':' in tz):
            tz = '-' + ''.join(tz.split(':'))
    micros = '000000'
    if ('.' in time):
        time, micros = time.split('.')
        if (len(micros) < 6):
            micros = micros + '0' * (6 - len(micros))
        elif (len(micros) > 6):
            micros = micros[:6]
    value = date + ' ' + time + '.' + micros + tz
    return datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S.%f%z')


def load_road_graph(json_path):
    with open(json_path, 'r', encoding='utf-8') as f:
        json_data = json.load(f)

    nodes = json_data["rd_jc"]
    edges = json_data["rd_el"]
    objects = json_data["objects"]
    conds = json_data.get("cond", None)

    return nodes, edges, objects, conds


def save_road_graph(nodes, edges, objects, json_path):
    data = {}
    if objects is not None:
        data["objects"] = objects
    if nodes is not None:
        data["rd_jc"] = nodes
    if edges is not None:
        data["rd_el"] = edges
    with open(json_path, 'w',  encoding='utf-8') as f:
        json.dump(data, f, indent=4, ensure_ascii=False)


def filter_edges_by_fc(edges, fc_min):
    return [edge for edge in edges if (edge["fc"] < fc_min)]


def rest_only_valid_signs_at_edge(edges, sign_ids):
    for edge in edges:
        edge["sign_ids_f"] = [id for id in edge["sign_ids_f"] if id in sign_ids]
        edge["sign_ids_t"] = [id for id in edge["sign_ids_t"] if id in sign_ids]
    return edges


def _extract_sign_ids(edges):
    ids = []
    for edge in edges:
        ids += edge["sign_ids_f"]
        ids += edge["sign_ids_t"]
    return ids


def filter_objects(objects, filter_func):
    return [obj for obj in objects if filter_func(obj)]


def make_filter_objects_by_type(prefix):
    def filter_by_type(prefix, obj):
        return (prefix in obj["sign_type"])
    return functools.partial(filter_by_type, prefix)


def make_filter_objects_by_types(types_list):
    def filter_by_type(types_list, obj):
        return (obj["sign_type"] in types_list)
    return functools.partial(filter_by_type, types_list)


def make_filter_objects_by_date(date):
    def filter_by_date(date, obj):
        return (date <= convertSQLDateTimeToTimestamp(obj["to_time"]))
    return functools.partial(filter_by_date, date)


def make_filter_objects_by_ids(sign_ids):
    def filter_by_ids(sign_ids, obj):
        return (obj["id"] in sign_ids)
    return functools.partial(filter_by_ids, sign_ids)


def remove_objects_wo_edges(objects, edges):
    return filter_objects(objects, make_filter_objects_by_ids(_extract_sign_ids(edges)))


def remove_objects_by_types(objects, types_list):
    filter_func = make_filter_objects_by_types(types_list)
    return [obj for obj in objects if not filter_func(obj)]


def remove_objects_by_date(objects, min_date):
    filter_func = make_filter_objects_by_date(min_date)
    return [obj for obj in objects if filter_func(obj)]
