import sys
sys.setrecursionlimit(20000)
import time
import random
import csv

from code.LinkedList import *
from code.HashTable import *
from code.BinaryTree import *



def generate_data(n=10000):
    return [(f"User_{i:05d}", f"+7-900-{i:05d}") for i in range(n)]


def prepare_data(n=10000):
    data = generate_data(n)

    shuffled = data[:]
    random.shuffle(shuffled)

    sorted_data = sorted(data, key=lambda x: x[0])

    return shuffled, sorted_data



def measure_find(find_func, obj, data):
    exist = random.sample([x[0] for x in data], 100)
    fake = [f"None_{i}" for i in range(10)]
    names = exist + fake

    start = time.perf_counter()

    for name in names:
        find_func(obj, name)

    return time.perf_counter() - start



def measure_delete(delete_func, obj, data):
    names = random.sample([x[0] for x in data], 50)

    start = time.perf_counter()

    for name in names:
        obj = delete_func(obj, name)

    return time.perf_counter() - start



def test_linked_list(data):
    head = None

    start = time.perf_counter()
    for name, phone in data:
        head = ll_insert(head, name, phone)
    insert_time = time.perf_counter() - start

    find_time = measure_find(ll_find, head, data)
    delete_time = measure_delete(ll_delete, head, data)

    return insert_time, find_time, delete_time



def test_hash_table(data):
    buckets = create_buckets(1000)

    start = time.perf_counter()
    for name, phone in data:
        ht_insert(buckets, name, phone)
    insert_time = time.perf_counter() - start

    find_time = measure_find(ht_find, buckets, data)
    delete_time = measure_delete(ht_delete, buckets, data)

    return insert_time, find_time, delete_time


def test_bst(data):
    root = None

    start = time.perf_counter()
    for name, phone in data:
        root = bst_insert(root, name, phone)
    insert_time = time.perf_counter() - start

    find_time = measure_find(bst_find, root, data)
    delete_time = measure_delete(bst_delete, root, data)

    return insert_time, find_time, delete_time


def run():

    results = []
    results.append(["Structure", "Order", "Insert", "Find", "Delete"])

    for i in range(5):   

        shuffled, sorted_data = prepare_data()

        # -------- LinkedList --------
        i1, f1, d1 = test_linked_list(shuffled)
        results.append(["LinkedList", "shuffled", i1, f1, d1])

        i1, f1, d1 = test_linked_list(sorted_data)
        results.append(["LinkedList", "sorted", i1, f1, d1])

        # -------- HashTable --------
        i2, f2, d2 = test_hash_table(shuffled)
        results.append(["HashTable", "shuffled", i2, f2, d2])

        i2, f2, d2 = test_hash_table(sorted_data)
        results.append(["HashTable", "sorted", i2, f2, d2])

        # -------- BST --------
        i3, f3, d3 = test_bst(shuffled)
        results.append(["BST", "shuffled", i3, f3, d3])

        i3, f3, d3 = test_bst(sorted_data)
        results.append(["BST", "sorted", i3, f3, d3])



    with open("results.csv", "w", newline="") as f:
        writer = csv.writer(f)
        writer.writerows(results)

    print("Готово! results.csv создан")


if __name__ == "__main__":
    run()