from datetime import datetime

import yandex.cloud.priv.loadtesting.agent.v1.trail_service_pb2 as messages
from load.projects.cloud.loadtesting.db.tables import JobTable
from load.projects.cloud.loadtesting.db.connection import get_clickhouse_client


def escape_string(s):
    return s.replace('\\', '\\\\').replace("'", "\\'")


def _insert_items_aka_lunapark(items, job: JobTable) -> None:
    """
    скопировано из load/projects/lunapark/www/api/views/jobtrailpush.py : insert_items
    """
    # TODO: remake tank datauploader
    # This is stupid, but it's the only way to support singlequotes in tags;
    rt_details_data = [
        "('%s', %s, '%s', '%s', %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
        % (
            str(job.started_at.date()),
            int(job.n),
            escape_string(item['case']),
            int(item['trail']['time'])
            if str(item['trail']['time']).isdigit() or isinstance(item['trail']['time'], float)
            else datetime.strftime(datetime.strptime(item['trail']['time'], '%Y-%m-%d %H:%M:%S'), '%Y-%m-%d %H:%M:%S'),
            int(item['trail']['connect_time'] * item['trail']['resps'] * 1000),
            int(item['trail']['send_time'] * item['trail']['resps'] * 1000),
            int(item['trail']['latency'] * item['trail']['resps'] * 1000),
            int(item['trail']['receive_time'] * item['trail']['resps'] * 1000),
            int(item['trail']['reqps']),
            int(item['trail']['resps']),
            int(item['trail']['threads']),
            int(item['trail']['input']),
            int(item['trail']['output']),
            0,
        )
        for item in items
    ]
    rt_quantiles_data = [
        "('%s', %s, '%s', '%s', %s, %s, %s, %s, %s, %s, %s, %s, %s)"
        % (
            str(job.started_at.date()),
            int(job.n),
            escape_string(item['case']),
            int(item['trail']['time'])
            if str(item['trail']['time']).isdigit() or isinstance(item['trail']['time'], float)
            else datetime.strftime(datetime.strptime(item['trail']['time'], '%Y-%m-%d %H:%M:%S'), '%Y-%m-%d %H:%M:%S'),
            float(item['trail']['q50']),
            float(item['trail']['q75']),
            float(item['trail']['q80']),
            float(item['trail']['q85']),
            float(item['trail']['q90']),
            float(item['trail']['q95']),
            float(item['trail']['q98']),
            float(item['trail']['q99']),
            float(item['trail']['q100']),
        )
        for item in items
    ]
    net_codes_data = []
    proto_codes_data = []
    rt_histograms_data = []
    for item in items:
        if item['net_codes']:
            net_codes_data.extend([
                "('%s', %s, '%s', '%s', %s, %s)" %
                (
                    str(job.started_at.date()),
                    int(job.n),
                    escape_string(item['case']),
                    int(item['trail']['time'])
                    if str(item['trail']['time']).isdigit() or isinstance(item['trail']['time'], float)
                    else datetime.strftime(datetime.strptime(item['trail']['time'], '%Y-%m-%d %H:%M:%S'),
                                           '%Y-%m-%d %H:%M:%S'),
                    int(net_codes['code']),
                    int(net_codes['count']),
                )
                for net_codes in item['net_codes']
            ])
        if item['http_codes']:
            proto_codes_data.extend([
                "('%s', %s, '%s', '%s', %s, %s)" % (
                    str(job.started_at.date()),
                    int(job.n),
                    escape_string(item['case']),
                    int(item['trail']['time'])
                    if str(item['trail']['time']).isdigit() or isinstance(item['trail']['time'], float)
                    else datetime.strftime(datetime.strptime(item['trail']['time'], '%Y-%m-%d %H:%M:%S'),
                                           '%Y-%m-%d %H:%M:%S'),
                    int(proto_codes['code']),
                    int(proto_codes['count']),
                )
                for proto_codes in item['http_codes']
            ])
        if item['time_intervals']:
            rt_histograms_data.extend([
                "('%s', %s, '%s', '%s', %s, %s)" % (
                    str(job.started_at.date()),
                    int(job.n),
                    escape_string(item['case']),
                    int(item['trail']['time'])
                    if str(item['trail']['time']).isdigit() or isinstance(item['trail']['time'], float)
                    else datetime.strftime(datetime.strptime(item['trail']['time'], '%Y-%m-%d %H:%M:%S'),
                                           '%Y-%m-%d %H:%M:%S'),
                    int(float(time_intervals['to']) * 1000),
                    int(time_intervals['count']),
                )
                for time_intervals in item['time_intervals']
            ])

    with get_clickhouse_client() as client:
        if rt_details_data:
            insert_rt_details_query = 'insert into loadtesting.rt_microsecond_details_buffer values %s' % ','.join(
                t for t in rt_details_data)
            client.execute(insert_rt_details_query)
        if rt_quantiles_data:
            insert_rt_quantiles_query = 'insert into loadtesting.rt_quantiles_buffer values %s' % ','.join(
                t for t in rt_quantiles_data)
            client.execute(insert_rt_quantiles_query)
        if net_codes_data:
            insert_net_codes_query = 'insert into loadtesting.net_codes_buffer values %s' % ','.join(
                t for t in net_codes_data)
            client.execute(insert_net_codes_query)
        if proto_codes_data:
            insert_proto_codes_query = 'insert into loadtesting.proto_codes_buffer values %s' % ','.join(
                t for t in proto_codes_data)
            client.execute(insert_proto_codes_query)
        if rt_histograms_data:
            insert_rt_histograms_query = 'insert into loadtesting.rt_microsecond_histograms_buffer values %s' % ','.join(
                t for t in rt_histograms_data)
            client.execute(insert_rt_histograms_query)


def _to_lunapark_style(create_trail: messages.CreateTrailRequest):
    items = []
    for trail in create_trail.data:
        item = {
            'case': trail.case_id,
            'trail': {
                'time': trail.time,
                'connect_time': trail.connect_time,
                'resps': trail.resps,
                'reqps': trail.reqps,
                'send_time': trail.send_time,
                'latency': trail.latency,
                'receive_time': trail.receive_time,
                'threads': trail.threads,
                'input': trail.input,
                'output': trail.output,
                'q50': trail.q50,
                'q75': trail.q75,
                'q80': trail.q80,
                'q85': trail.q85,
                'q90': trail.q90,
                'q95': trail.q95,
                'q98': trail.q98,
                'q99': trail.q99,
                'q100': trail.q100,
            },
            'net_codes': [
                {
                    'code': c.code,
                    'count': c.count
                }
                for c in trail.net_codes
            ],
            'http_codes': [
                {
                    'code': c.code,
                    'count': c.count
                }
                for c in trail.http_codes
            ],
            'time_intervals': [
                {
                    'count': i.count,
                    'to': i.to
                }
                for i in trail.time_intervals
            ],
        }
        items.append(item)
    return items


def push_to_clickhouse(create_trail: messages.CreateTrailRequest, job: JobTable):
    lunapark_style_params = _to_lunapark_style(create_trail)
    _insert_items_aka_lunapark(lunapark_style_params, job)
