import random
import time
import matplotlib.pyplot as plt
import sys


def read_input(filename: str):
    with open(filename, "r") as f:
        return [int(line.strip()) for line in f]


def smallest_difference_brute_force(array):
    """
       Returns the minimum difference between any two array elements

       Args:
           array (list): The values to be considered.

       Tests:
           >>> smallest_difference_brute_force([-100, -10, 10, 100])
           20
    """
    n = len(array)
    best_difference = sys.maxsize
    for i in range(n):
        for j in range(i+1, n):
            if abs(array[i] - array[j]) < best_difference:
                best_difference = abs(array[i] - array[j])
    return best_difference


def smallest_difference_faster(array):
    """
       Returns the minimum difference between any two array elements

       Args:
           array (list): The values to be considered.

       Tests:
           >>> smallest_difference_brute_force([-100, -10, 10, 100])
           20

           >>> smallest_difference_brute_force([-100, 10, 100])
           90

           >>> smallest_difference_brute_force([-100, 10, 100, 15, 30, -20])
           5

           >>> smallest_difference_brute_force([-100, 10, 15, 30, -20, -18])
           2

           >>> smallest_difference_brute_force([-10,10])
           20
    """
    n = len(array)
    sorted_array = sorted(array)
    best_difference = sys.maxsize

    for i in range(n-1):
        if abs(sorted_array[i] - sorted_array[i+1]) < best_difference:
            best_difference = abs(sorted_array[i] - sorted_array[i+1])
    return best_difference

###############################################################################
###############################################################################
###############################################################################


def time_measurement(algorithm, size_range, verifier=None):
    """
       Performs timed tests and returns time measurements.

       Args:
           algorithm: The sorting algorithm to be tested.
           size_range (range): specifies the input sizes for the measurements.

       Returns:
           list: list of execution times.

    """
    results = []
    # Loop from 'skip' up to 'range_n', stepping by 'skip'
    for n in size_range:
        input = [random.randint(0, 10000) for _ in range(n)]
        start_time = time.time()
        output = algorithm(input)
        end_time = time.time()
        results.append(end_time - start_time)

        # Verify that the array was actually sorted
        if verifier is not None:
            if not verifier(input, output):
                raise Exception("Verifier complained!")

    return results


def plot_results(x_values, algorithm_data, use_log_scale=False):
    """
    Plots the execution times of the sorting algorithms.

    Args:
        x_values (list): The input sizes (n) tested.
        algorithm_data (list): Pairs of algorithm names and runtime data.
        use_log_scale (bool): If True, plots the Y-axis on a logarithmic scale.
    """
    plt.figure(figsize=(10, 6))

    # Plot algorithms
    for (algo_name, times) in algorithm_data:
        plt.plot(x_values, times, label=algo_name, linewidth=2)

    # Adjust axis and titles based on the scale choice
    if use_log_scale:
        plt.yscale('log')
        plt.ylabel('Execution Time (seconds) [Log Scale]')
        plt.title('Time Complexity (Logarithmic Scale)')
    else:
        plt.ylabel('Execution Time (seconds)')
        plt.title('Time Complexity')

    # Format the rest of the chart
    plt.xlabel('Input Size (n)')
    plt.legend()
    plt.grid(True, linestyle='--', alpha=0.7)

    # Display the plot
    plt.tight_layout()
    plt.show()


def compare_runtimes(use_log_scale=False):
    size_range = range(100, 10001, 100)

    print("Measuring brute force approach... (This might take some time)")
    brute_force_times = time_measurement(
        smallest_difference_brute_force, size_range)
    print("Done...")

    print("Measuring faster approach ... (hopefully this is faster)")
    faster_times = time_measurement(smallest_difference_faster, size_range)
    print("Done...")

    times = [("Brute Force", brute_force_times), ("Faster", faster_times)]
    # Generate the x-axis values to match the 'n' sizes used in the loop
    x_values = list(size_range)

    # Create the plot
    plot_results(x_values, times, use_log_scale)


if __name__ == "__main__":
    # compare_runtimes()
    print(smallest_difference_faster(read_input('input.txt')))
