import time
from .ll import ll_insert, ll_find, ll_delete
from .ht import ht_new, ht_insert, ht_find, ht_delete
from .bst import bst_insert, bst_find, bst_delete


def _build_ll(records):
    head = None
    for name, phone in records:
        head = ll_insert(head, name, phone)
    return head


def _build_ht(records):
    buckets = ht_new()
    for name, phone in records:
        ht_insert(buckets, name, phone)
    return buckets


def _build_bst(records):
    root = None
    for name, phone in records:
        root = bst_insert(root, name, phone)
    return root


def _time_insert(build_fn, records):
    start = time.perf_counter()
    structure = build_fn(records)
    end = time.perf_counter()
    elapsed = end - start
    return elapsed, structure


def _time_find(find_fn, structure, names):
    start = time.perf_counter()
    for name in names:
        find_fn(structure, name)
    end = time.perf_counter()
    elapsed = end - start
    return elapsed


def _time_delete(delete_fn, structure, names):
    start = time.perf_counter()
    for name in names:
        result = delete_fn(structure, name)
        if result is not None:
            structure = result
    end = time.perf_counter()
    elapsed = end - start
    return elapsed, structure


def run_once(records, search_names, delete_names):
    results = []

    structures = {
        'LinkedList': (_build_ll, ll_find, ll_delete),
        'HashTable':  (_build_ht, ht_find, ht_delete),
        'BST':        (_build_bst, bst_find, bst_delete),
    }

    for label, (build_fn, find_fn, delete_fn) in structures.items():
        t_insert, structure = _time_insert(build_fn, records)
        t_find = _time_find(find_fn, structure, search_names)
        t_delete, structure = _time_delete(delete_fn, structure, delete_names)

        results.append((label, t_insert, t_find, t_delete))

    return results
