import math
import random

VN_list_char = "aAàÀảẢãÃáÁạẠăĂằẰẳẲẵẴắẮặẶâÂầẦẩẨẫẪấẤậẬbBcCdDđĐeEèÈẻẺẽẼéÉẹẸêÊềỀểỂễỄếẾệỆfFgGhHiIìÌỉỈĩĨíÍịỊjJkKlLmMnNoOòÒỏỎõÕóÓọỌôÔồỒổỔỗỖốỐộỘơƠờỜởỞỡỠớỚợỢpPqQrRsStTuUùÙủỦũŨúÚụỤưƯừỪửỬữỮứỨựỰvVwWxXyYỳỲỷỶỹỸýÝỵỴzZ0123456789!#$%&()*+,-./:;<=>?@[\]^_`{|}~"


def perturbate_character(words: list, ratio=0.01):
    # Algorithm
    # Step 1: couting number of characters is words and sample the postion we want to perturbation
    # ( words = ["abc", "lkdhf", "lfhdlsa", "akdjhf"] =>> total_char = 21, pertubation_position = [15,13,7]), these are the positions of perturbating chars in the concatenating string of words "abclkdhflfhdlsaakdjhf"
    # start_pos = 0, ending_pos = 0
    # Step 2: with each word in words, calculate the start_position and ending_pos of word in the concatenating string
    # if ending pos > pertubation_position[-1] => conduct perturbation and plus 1 to perturbation index, else => continue
    # Loop 1: words[0], start_pos = 0 ,ending_pos= 3 <= pertubation_position[-1] =7 => continue
    # Loop 2:

    total_char = sum(len(i) for i in words)
    pertubation_positions = sorted(
        random.sample(range(total_char), int(ratio * total_char))
    )
    # logging.info(pertubation_positions)
    pos = 0
    start_pos = 0
    j = 0
    for i, word in enumerate(words):
        if j == len(pertubation_positions):
            break
        start_pos = pos
        pos += len(word)
        # logging.info(start_pos,pos)
        while pos > pertubation_positions[j]:
            x = random.randint(0, 3)
            fixing_pos = pertubation_positions[j] - start_pos
            if x == 0:  # append random char to the left
                word = (
                    word[:fixing_pos]
                    + VN_list_char[random.randint(0, len(VN_list_char) - 1)]
                    + word[fixing_pos:]
                )

            if x == 1:  # append random char to the right
                word = (
                    word[: fixing_pos + 1]
                    + VN_list_char[random.randint(0, len(VN_list_char) - 1)]
                    + word[fixing_pos + 1 :]
                )

            if x == 2:  # adjust to another random char at current position
                word = (
                    word[:fixing_pos]
                    + VN_list_char[random.randint(0, len(VN_list_char) - 1)]
                    + word[fixing_pos + 1 :]
                )

            if x == 3 and len(word) > 1:  # delete char at current position

                word = word[:fixing_pos] + word[fixing_pos + 1 :]

            j += 1
            # logging.info(words[i], word)
            words[i] = word
            if j == len(pertubation_positions):
                break

    return words


def sampling_data(words, boxes, labels, max_num_words=150, slice_interval=50):
    # num_boxes = len(words)
    # if num_boxes > max_num_words:
    #     slide = max_num_words // 2
    #     num_batches = math.ceil(num_boxes / slide)

    #     idx_batches = [i for i in range(num_batches)]
    #     idx_batch = random.choice(idx_batches)
    #     start_idx = slide * idx_batch
    #     words = words[start_idx:]
    #     normalized_word_boxes = normalized_word_boxes[start_idx:]
    #     word_labels = normalized_word_boxes[start_idx:]

    total_word = len(words)
    window_size = max_num_words
    text_windows = [
        words[i : i + window_size] for i in range(0, total_word, slice_interval)
    ]
    box_windows = [
        boxes[i : i + window_size] for i in range(0, total_word, slice_interval)
    ]
    label_windown = [
        labels[i : i + window_size] for i in range(0, total_word, slice_interval)
    ]

    # assert all(
    #     [
    #         len(_words) == len(boxes)
    #         for _words, boxes in zip(words, normalized_word_boxes)
    #     ]
    # )
    # assert all(
    #     [
    #         len(_words) == len(_word_labels)
    #         for _words, _word_labels in zip(words, word_labels)
    #     ]
    # )
    sampling_idx = random.choice([i for i in range(len(text_windows))])
    sampling_words, sampling_boxes, sampling_labels = (
        text_windows[sampling_idx],
        box_windows[sampling_idx],
        label_windown[sampling_idx],
    )

    return sampling_idx, sampling_words, sampling_boxes, sampling_labels
