"""
plot_results.py - строит столбчатые диаграммы по итогам экспериментов.
"""
import csv
import os
import matplotlib.pyplot as plt
import numpy as np

CSV = os.path.join("docs", "data", "results.csv")
PLOTS_DIR = os.path.join("docs", "data", "plots")
os.makedirs(PLOTS_DIR, exist_ok=True)


def load_means():
    """Возвращает dict[(structure, mode, op)] = (mean, N)."""
    means = {}
    with open(CSV, encoding="utf-8") as f:
        rows = list(csv.reader(f))
    # ищем секцию "--- СРЕДНИЕ ---"
    start = None
    for i, row in enumerate(rows):
        if row and row[0] == "--- СРЕДНИЕ ---":
            start = i + 2  # пропустить заголовок секции
            break
    for row in rows[start:]:
        if not row:
            continue
        structure, mode, op, n, mean, _trials = row
        means[(structure, mode, op)] = (float(mean), int(n))
    return means


def plot_grouped(means, op, fname, title):
    """Сгруппированные столбцы: для каждой структуры - два столбца (shuffled / sorted)."""
    structures = ["LinkedList", "HashTable", "BST"]
    modes = ["shuffled", "sorted"]
    x = np.arange(len(structures))
    width = 0.36

    fig, ax = plt.subplots(figsize=(8, 5))

    for i, mode in enumerate(modes):
        vals_ms = []
        labels = []
        for s in structures:
            mean, n = means[(s, mode, op)]
            vals_ms.append(mean * 1000)
            labels.append(f"N={n}")
        bars = ax.bar(x + (i - 0.5) * width, vals_ms, width,
                      label=mode, alpha=0.85)
        for bar, lab in zip(bars, labels):
            h = bar.get_height()
            ax.text(bar.get_x() + bar.get_width() / 2, h,
                    f"{h:.2f}\n{lab}", ha="center", va="bottom", fontsize=8)

    ax.set_xticks(x)
    ax.set_xticklabels(structures)
    ax.set_ylabel("Время, мс (среднее по 5 запускам)")
    ax.set_title(title)
    ax.set_yscale("log")
    ax.legend(title="порядок входных данных")
    ax.grid(axis="y", linestyle="--", alpha=0.4)
    plt.tight_layout()
    out = os.path.join(PLOTS_DIR, fname)
    plt.savefig(out, dpi=130)
    plt.close()
    print("saved:", out)


def plot_bst_degradation(means, fname):
    """Отдельный график: BST shuffled vs sorted - даже при меньшем N
    отсортированные данные дают намного большее время."""
    ops = ["insert", "find", "delete"]
    shuffled = [means[("BST", "shuffled", op)][0] * 1000 for op in ops]
    sorted_  = [means[("BST", "sorted",   op)][0] * 1000 for op in ops]
    n_shuf   = means[("BST", "shuffled", "insert")][1]
    n_sort   = means[("BST", "sorted",   "insert")][1]

    x = np.arange(len(ops))
    width = 0.36
    fig, ax = plt.subplots(figsize=(7, 4.5))
    ax.bar(x - width/2, shuffled, width, label=f"shuffled (N={n_shuf})")
    ax.bar(x + width/2, sorted_,  width, label=f"sorted (N={n_sort})")
    for i, v in enumerate(shuffled):
        ax.text(i - width/2, v, f"{v:.2f}", ha="center", va="bottom", fontsize=9)
    for i, v in enumerate(sorted_):
        ax.text(i + width/2, v, f"{v:.2f}", ha="center", va="bottom", fontsize=9)

    ax.set_xticks(x); ax.set_xticklabels(ops)
    ax.set_ylabel("Время, мс")
    ax.set_title("BST: деградация на отсортированных данных\n"
                 "(N для sorted в 5 раз меньше, но время больше)")
    ax.set_yscale("log")
    ax.legend()
    ax.grid(axis="y", linestyle="--", alpha=0.4)
    plt.tight_layout()
    out = os.path.join(PLOTS_DIR, fname)
    plt.savefig(out, dpi=130)
    plt.close()
    print("saved:", out)


def main():
    means = load_means()
    plot_grouped(means, "insert",
                 "insert_compare.png",
                 "Вставка всех записей (лог. шкала)")
    plot_grouped(means, "find",
                 "find_compare.png",
                 "Поиск 110 ключей (лог. шкала)")
    plot_grouped(means, "delete",
                 "delete_compare.png",
                 "Удаление 50 записей (лог. шкала)")
    plot_bst_degradation(means, "bst_degradation.png")


if __name__ == "__main__":
    main()
