import random
import time 
import csv
import sys

sys.setrecursionlimit(20000)

from codes.LL import ll_insert, ll_find, ll_delete
from codes.HT import ht_insert, ht_delete, ht_find
from codes.BST import bst_delete, bst_find, bst_insert

# Экспериментальная часть
def generate_records(N):
    records =[]
    for i in range(N):
        name = f"User_{i:05d}"
        phone =str(random.randint(100000,999999))
        records.append((name,phone))
    return records


def run_test(structure_name, mode, input_data, search_names, delete_names):
    print(f"Тест {structure_name} в режиме {mode}")
    ins_times = []
    find_times = []
    del_times = []
    for _ in range(5):
        if structure_name == "LL":
            container = None
        elif structure_name == "BST":
            container = None
        elif structure_name == "HT":
            container = [None]*150
        #А
        start = time.perf_counter()
        for name, phone in input_data:
            if structure_name == "LL": 
                container = ll_insert(container, name, phone)
            elif structure_name == "BST": 
                container = bst_insert(container, name, phone)
            elif structure_name == "HT": 
                ht_insert(container, name, phone) 
        ins_times.append(time.perf_counter() - start)
        #Б
        start = time.perf_counter()
        for name in search_names:
            if structure_name == "LL": ll_find(container, name)
            elif structure_name == "BST": bst_find(container, name)
            else: ht_find(container, name)
        find_times.append(time.perf_counter() - start)
        #В
        start = time.perf_counter()
        for name in delete_names:
            if structure_name == "LL": container = ll_delete(container, name)
            elif structure_name == "BST": container = bst_delete(container, name)
            else: ht_delete(container, name)
        del_times.append(time.perf_counter() - start)
  
    results = []

    for i in range(5):
        results.append([structure_name, mode, f"Вставка (попытка {i+1})", ins_times[i]])
    results.append([structure_name, mode, "Вставка СРЕДНЕЕ", sum(ins_times) / 5])

    for i in range(5):
        results.append([structure_name, mode, f"Поиск (попытка {i+1})", find_times[i]])
    results.append([structure_name, mode, "Поиск СРЕДНЕЕ", sum(find_times) / 5])

    for i in range(5):
        results.append([structure_name, mode, f"Удаление (попытка {i+1})", del_times[i]])
    results.append([structure_name, mode, "Удаление СРЕДНЕЕ", sum(del_times) / 5])

    return results

def main_experiment():
    N = 10000

    data = generate_records(N)
    random.shuffle(data)
    data_sort = sorted(data, key = lambda x: x[0])

    search_names = [r[0] for r in random.sample(data, 100)] + [f"None_{i}" for i in range(10)]
    delete_names = [r[0] for r in random.sample(data, 50)] 

    results = [["Structure", "Mode", "Operation", "Time"]]

    for mode_name, mode_data in [("shufled", data), ("sorted", data_sort)]:
        results += run_test("LL", mode_name, mode_data, search_names, delete_names)
        results += run_test("BST", mode_name, mode_data, search_names, delete_names)
        results += run_test("HT", mode_name, mode_data, search_names, delete_names)


        
    with open("results.csv", "w", newline = "") as f:
        writer = csv.writer(f)
        writer.writerows(results)
    print("Результаты сохранены в файл")


if __name__ == "__main__":
    main_experiment()