import time
import numpy as np
from linkedlist import ll_insert, ll_find, ll_delete
from hashtable import ht_create, ht_insert, ht_find, ht_delete
from bst import bst_insert, bst_find, bst_delete

def measure_insert(records, struct_type, params=None): #Замер времени вставки всех записей
    start = time.perf_counter()
    
    if struct_type == 'linkedlist':
        head = None
        for name, phone in records:
            head = ll_insert(head, name, phone)
        result = head
    
    elif struct_type == 'hashtable':
        size = params.get('size', 1000) if params else 1000
        buckets = ht_create(size)
        for name, phone in records:
            ht_insert(buckets, name, phone)
        result = buckets
    
    elif struct_type == 'bst':
        root = None
        for name, phone in records:
            root = bst_insert(root, name, phone)
        result = root
    
    end = time.perf_counter()
    return end - start, result

def measure_find(structure, names_to_find, struct_type): #Замер времени поиска записей
    start = time.perf_counter()
    
    for name in names_to_find:
        if struct_type == 'linkedlist':
            ll_find(structure, name)
        elif struct_type == 'hashtable':
            ht_find(structure, name)
        elif struct_type == 'bst':
            bst_find(structure, name)
    
    end = time.perf_counter()
    return end - start

def measure_delete(structure, names_to_delete, struct_type): #Замер времени удаления записей
    start = time.perf_counter()
    
    for name in names_to_delete:
        if struct_type == 'linkedlist':
            structure = ll_delete(structure, name)
        elif struct_type == 'hashtable':
            ht_delete(structure, name)
        elif struct_type == 'bst':
            structure = bst_delete(structure, name)
    
    end = time.perf_counter()
    return end - start, structure

def run_single_experiment(struct_type, mode, data_records, names_to_find, names_to_delete, repeats, params=None): #Запуск одного эксперимента
    insert_times = []
    find_times = []
    delete_times = []
    
    for i in range(repeats):
        if struct_type == 'hashtable':
            insert_time, structure = measure_insert(data_records, struct_type, params)
        else:
            insert_time, structure = measure_insert(data_records, struct_type)
        insert_times.append(insert_time)
        
        find_time = measure_find(structure, names_to_find, struct_type)
        find_times.append(find_time)

        delete_time, structure = measure_delete(structure, names_to_delete, struct_type)
        delete_times.append(delete_time)
    
    return {
        'structure': struct_type,
        'mode': mode,
        'insert_mean': np.mean(insert_times),
        'insert_std': np.std(insert_times),
        'insert_all': insert_times,
        'find_mean': np.mean(find_times),
        'find_std': np.std(find_times),
        'find_all': find_times,
        'delete_mean': np.mean(delete_times),
        'delete_std': np.std(delete_times),
        'delete_all': delete_times
    }