import time
import random
import csv
import structures as st  # Предполагается, что у вас есть модуль с реализациями структур данных

N=10000
REPEATS=5

# Генерируем список записей из N элементов, каждая запись - имя и телефон
def generate_records(N):
    records = [
        (f"User_{i:05d}", f"+7{random.randint(10**9, 10**10 - 1)}")
        for i in range(N)
    ]
    return records, sorted(records, key=lambda x: x[0])

# Подготовка списка имен, которые нужно искать: Некоторые точно есть, некоторые — придуманные
def prepare_find_names(records, n_exist=100, n_missing=10):
    existing_names = [name for name, _ in records]
    find_existing = random.sample(existing_names, n_exist)  # Имена, которые есть
    find_missing = [f"None_{i}" for i in range(n_missing)]  # Не существующие имена
    return find_existing + find_missing

# Подготовка списка имен для удаления
def prepare_delete_names(records, n_delete=50):
    existing_names = [name for name, _ in records]
    return random.sample(existing_names, n_delete)  # случайные имена для удаления

# Обертка для измерения времени выполнения функции
def measure_time(func, *args):
    start = time.perf_counter()  # Точное время начала
    result = func(*args)          # Вызов функции
    return result, time.perf_counter() - start  # Возвращаем результат и время выполнения

# Определение структур данных и соответствующих функций для операций
STRUCTURES = [
    ("LinkedList", st.ll_insert, st.ll_find, st.ll_delete),
    ("HashTable", st.ht_insert, st.ht_find, st.ht_delete),
    ("BST", st.bst_insert, st.bst_find, st.bst_delete),
]

# Функция для построения структуры данных из записей и измерения времени вставки
def build_and_measure(build_func, records, init_val):
    head = init_val
    for name, phone in records:
        head = build_func(head, name, phone)  # Построение структуре поэлементно
    return head  # Возвращает финальную структуру

# Основная функция для запуска одного эксперимента
def run_one_experiment(records_shuffled, records_sorted, find_names, delete_names):
    results = []
    for mode, recs in [("shuffled", records_shuffled), ("sorted", records_sorted)]:
        for name, build_fn, find_fn, delete_fn in STRUCTURES:
            init_val = None if name in ("LinkedList", "BST") else [None] * 10007
            head, t_insert = measure_time(build_and_measure, build_fn, recs, init_val)

            # Создаем функции для поиска и удаления с фиксированными параметрами
            def search_fn():
                return [find_fn(head, n) for n in find_names]

            def delete_fn_wrapper():
                return [delete_fn(head, n) for n in delete_names]

            t_find = measure_time(search_fn)[1]
            t_delete = measure_time(delete_fn_wrapper)[1]

            results += [
                [name, mode, "insert", t_insert],
                [name, mode, "find", t_find],
                [name, mode, "delete", t_delete],
            ]
    return results

# Генерация исходных данных
records_shuffled, records_sorted = generate_records(N)

# Подготовка списков имен для поиска и удаления
find_names = prepare_find_names(records_sorted)
delete_names = prepare_delete_names(records_sorted)

# Заголовки результатов
results = [["Запуск", "Структура", "Режим", "Операция", "Время (сек)"]]

# Проведение серии запусков
for run in range(1, REPEATS+1):
    print(f"Запуск эксперимента: {run}")
    one_run_results = run_one_experiment(records_shuffled, records_sorted, find_names, delete_names)
    for struct, mode, op, t in one_run_results:
        results.append([run, struct, mode, op, t])  # Добавляем результаты каждого запуска

# Подсчет средних значений по результатам
groups = {}
for row in results[1:]:
    key = tuple(row[1:4])  # Ключ — название структуры, режим, тип операции
    groups.setdefault(key, []).append(row[4])  # Собираем времена для среднего

for key, times in groups.items():
    avg_time = sum(times)/len(times)
    results.append(["average"] + list(key) + [avg_time])  # Средний результат

# Запись итоговых данных в CSV файл
with open("results.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerows(results)

print("Результаты сохранены")