import csv
import time
import os
import matplotlib.pyplot as plt
import numpy as np

from MazeBuilder import TextFileMazeBuilder
from MazeSolver import MazeSolver, SearchStats
from DepthFirstSearch import DFSStrategy
from BreadthFirstSearch import BFSStrategy
from Deikstra import DeikstraFind
from AStarStrategy import AStarStrategy
from ConsoleView import ConsoleView


def run_benchmarks():

    files = ["mazes/maze_small.txt", "mazes/maze_empty.txt",
             "mazes/maze_no_exit.txt", "mazes/maze_medium.txt", "mazes/maze_large.txt"]
    strategies = {
        "BFS": BFSStrategy(),
        "DFS": DFSStrategy(),
        "A*": AStarStrategy(),
        "Deikstra": DeikstraFind()
    }

    view = ConsoleView()

    NUM_RUNS = 5
    results = []

    print("Запуск экспериментов...")

    for file in files:
        if not os.path.exists(file):
            print(f"Файл {file} не найден. Пропуск.")
            continue

        for name, strategy in strategies.items():
            total_time = 0.0
            visited_counts = []
            path_lengths = []

            print(f" работает {name}")
            for _ in range(NUM_RUNS):
                # Пересоздаем лабиринт
                builder = TextFileMazeBuilder()
                builder.buildFromFile(file)
                maze = builder.maze

                solver = MazeSolver(maze, strategy)

                solver.addObserver(view)

                stats = solver.solve()

                total_time += stats.execution_time
                visited_counts.append(stats.visited_count)
                path_lengths.append(stats.path_length)

            # средние значения
            avg_time = total_time / NUM_RUNS
            avg_visited = int(np.mean(visited_counts))
            avg_path = int(np.mean(path_lengths))

            results.append({
                "лабиринт": file,
                "стратегия": name,
                "время_мс": round(avg_time, 4),
                "посещено_клеток": avg_visited,
                "длина_пути": avg_path
            })

    # Запись в CSV
    csv_file = "results/maze_benchmark_results.csv"
    with open(csv_file, mode="w", encoding="utf-8", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=[
                                "лабиринт", "стратегия", "время_мс", "посещено_клеток", "длина_пути"])
        writer.writeheader()
        writer.writerows(results)

    print(f"Результаты успешно сохранены в {csv_file}")
    return results

# Построение графиков


def plot_results(results):
    print("Генерация графиков...")
    mazes = sorted(list(set(r["лабиринт"] for r in results)))
    strategies = ["BFS", "DFS", "A*"]

    # График Количество посещенных клеток
    fig, ax = plt.subplots(figsize=(10, 6))
    x = np.arange(len(mazes))
    width = 0.25

    for i, strat in enumerate(strategies):
        visited = [next(r["посещено_клеток"] for r in results if r["лабиринт"]
                        == m and r["стратегия"] == strat) for m in mazes]
        ax.bar(x + i*width, visited, width, label=strat)

    ax.set_ylabel('Количество посещенных клеток')
    ax.set_title('Сравнение эффективности обхода лабиринтов (меньше = лучше)')
    ax.set_xticks(x + width)
    ax.set_xticklabels(mazes, rotation=15)
    ax.legend()
    plt.tight_layout()
    plt.savefig("results/benchmark_visited_cells.png", dpi=200)
    plt.savefig("results/benchmark_visited_cells.eps", dpi=200)
    plt.close()

    # График Время выполнения
    fig, ax = plt.subplots(figsize=(10, 6))
    for i, strat in enumerate(strategies):
        times = [next(r["время_мс"] for r in results if r["лабиринт"]
                      == m and r["стратегия"] == strat) for m in mazes]
        ax.bar(x + i*width, times, width, label=strat)

    ax.set_ylabel('Время выполнения (мс)')
    ax.set_title('Сравнение времени работы алгоритмов')
    ax.set_xticks(x + width)
    ax.set_xticklabels(mazes, rotation=15)
    ax.legend()
    plt.tight_layout()
    plt.savefig("results/benchmark_execution_time.png", dpi=200)
    plt.savefig("results/benchmark_execution_time.eps", dpi=200)
    plt.close()
    print("Графики сохранены в текущую директорию.")


if __name__ == "__main__":
    data = run_benchmarks()
    plot_results(data)
