import csv
import warnings
from .event_report_template import *


def set_bit_in_vector(enable, data, bit_no):

    bits_in_word = 32
    total_words = len(data)
    selected_word = int(bit_no / bits_in_word)
    bit_offset = bits_in_word - (((selected_word + 1) * bits_in_word) - bit_no)

    if selected_word >= total_words:
        warnings.warn(f"Bit {bit_no} is out of provided vector's range {total_words} words")
        return

    if enable:
        data[selected_word] |= (1 << bit_offset)
    else:
        data[selected_word] &= ~(1 << bit_offset)


def search_in_list(_type, _list):
    for item in enumerate(_list):
        if isinstance(item[1], _type):
            return item[0]

    return None


def byterarray_to_hex_str(data: bytearray) -> str:
    return ' '.join(format(x, '02x') for x in data)


def content_to_str(data: str) -> str:
    data = data.replace("\r\n", "<br>")
    data = data.replace("\n\r", "<br>")
    data = data.replace("\r", "<br>")
    data = data.replace("\n", "<br>")
    data = data.replace("'", "\\'")
    data = data.replace("  ", " &nbsp")
    return data


def timestamp_to_str(value) -> str:
    nsec = value % 1000
    value -= nsec
    value /= 1000

    mcsec = value % 1000
    value -= mcsec
    value /= 1000

    msec = value % 1000
    value -= msec
    value /= 1000

    sec = value % 60
    value -= sec
    value /= 60

    min_v = value % 60
    value -= min_v

    hour = value / 60

    return "{:02d}:{:02d}:{:02d}.{:03d}.{:03d}.{:03d}".format(int(hour), int(min_v), int(sec), int(msec), int(mcsec),
                                                              int(nsec))


def save_to_txt_file(path: str, events: list, index=None):
    file = open(path, 'w')
    if index is not None:
        if len(events[index]) == 6:
            file.write(f"{events[index].get('content')}\n{events[index].get('brief')}\n"
                       f"{byterarray_to_hex_str(events[index].get('data'))}\n"
                       f"{events[index].get('source')}\n")
        else:
            warnings.warn("Empty event")
    else:
        for data in events:
            if len(data) == 6:
                file.write(f"{data.get('content')}\n{data.get('brief')}\n"
                           f"{byterarray_to_hex_str(data.get('data'))}\n"
                           f"{data.get('source')}\n")
            else:
                warnings.warn("Empty event")

    file.close()


def save_to_bin_file(path: str, events: list, index=None):
    file = open(path, 'wb')
    if index is not None:
        data = events[index].data
        if len(data) > 14:
            sync = 0x0B41550B
            file.write(sync.to_bytes(length=4, byteorder='little'))
            file.write(0x0.to_bytes(length=4, byteorder='little'))
            file.write(int(data[13] & 0xF).to_bytes(length=4, byteorder='little'))
            file.write(int((len(data) - 12) / 4).to_bytes(length=4, byteorder='little'))
            file.write(data[12:])
    else:
        for data in events:
            if len(data.data) > 14:
                sync = 0x0B41550B
                file.write(sync.to_bytes(length=4, byteorder='little'))
                file.write(0x0.to_bytes(length=4, byteorder='little'))
                file.write(int(data.data[13] & 0xF).to_bytes(length=4, byteorder='little'))
                file.write(int((len(data.data) - 12) / 4).to_bytes(length=4, byteorder='little'))
                file.write(data.data[12:])
    file.close()


def save_to_csv_file(path: str, events: list):
    with (open(path, 'w', newline='') as file):
        writer = csv.writer(file, delimiter=';')
        writer.writerow(["Source", "Type", "Start", "Brief info", "Full info"])
        for data in events:
            if len(data) == 6:
                processed_info = data.get('content')[:-1] + '.'
                processed_info = processed_info.replace("\n", "; ")

                writer.writerow([
                    data.get('source'),
                    data.get('type'),
                    timestamp_to_str(data.get('timestamp')),
                    data.get('brief'),
                    f'"{processed_info}"'
                ])
            else:
                warnings.warn("Empty event")



def save_to_html_file(path: str, events: list, fw_info: dict, long_type_string: bool):
    file = open(path, 'w')

    new_events_template = events_template.replace("{$report_name}", "Unigraf UCD Console event monitoring report").\
        replace("{$bundle_version}", fw_info.get('bundle_version')).\
        replace("{$app_version}", fw_info.get('app_version')).\
        replace("{$frontend_version}", fw_info.get('frontend_version')).\
        replace("{$memory_size}", fw_info.get('memory_size')).\
        replace("{$ucd_device}", fw_info.get('ucd_device')).\
        replace("{$ucd_fw_version}", fw_info.get('ucd_fw_version')).\
        replace("{$remarks}", '').\
        replace("{$tested}", "")

    events_data = []
    entries_list = []
    entries_rows = []

    for index, item in enumerate(events):

        new_entry_value = event_entry_template.replace("{$event_name}", item.get('brief')).\
            replace("{$time}", f'{timestamp_to_str(item.get("timestamp"))}').\
            replace("{$entry_type}", "").\
            replace("{$send_from}", item.get('type')).\
            replace("{$num}", f'{index}').\
            replace("{$hex}", byterarray_to_hex_str(item.get('data'))).\
            replace("{$hex_just}", byterarray_to_hex_str(item.get('data'))).\
            replace("{$event_data}", content_to_str(item.get('content'))).\
            replace("{$num_just}", f"{index}".ljust(6, " ").replace(" ", "&nbsp")).\
            replace("{$send_from_just}", f"{item.get('source')}".ljust(10, " ").replace(" ", "&nbsp")).\
            replace("{$type_just}", f"{item.get('type')}".ljust(16 if long_type_string else 8, " ").replace(" ", "&nbsp")).\
            replace("{$text_color}", "#000000").\
            replace("{$back_color}", '#ffffff').\
            replace("{$font_bold}", "").\
            replace("{$font_italic}", "").\
            replace("{$font_family}", "")

        new_event_table_row = event_table_row.replace("{$text_color}", "#000000").\
            replace("{$back_color}", '#ffffff').\
            replace("{$font_family}", "").\
            replace("{$font_italic}", "").\
            replace("{$font_bold}", "").\
            replace("{$num}", f'{index}').\
            replace("{$num_just}", f"{index}".ljust(6, " ").replace(" ", "&nbsp")).\
            replace("{$time}", f'{timestamp_to_str(item.get("timestamp"))}').\
            replace("{$send_from_just}", f"{item.get('source')}".ljust(10, " ").replace(" ", "&nbsp")).\
            replace("{$type_just}", f"{item.get('type')}".ljust(16 if long_type_string else 8, " ").replace(" ", "&nbsp")).\
            replace("{$event_name}", item.get('brief'))

        events_data.append(new_entry_value)
        entries_rows.append(new_event_table_row)
        entries_list.append(f"Entry{index},")

    new_events_template = new_events_template.replace("{$events_data}", "\n".join(e for e in events_data)).\
        replace("{$events_list}", "\n".join(e for e in entries_list)).\
        replace("{$events_table}", "\n".join(e for e in entries_rows))

    file.write(new_events_template)
    file.close()
