import csv
import time
from typing import List, Dict
from models import Maze
from builders import TextFileMazeBuilder
from strategies import BFSStrategy, DFSStrategy, AStarStrategy
from solver import MazeSolver


def run_experiment(maze: Maze, strategy_name: str, strategy, repeats: int = 5) -> Dict:
    """Запускает эксперимент для одной стратегии"""
    times = []
    visited_counts = []
    path_lengths = []
    path_found = True
    
    for _ in range(repeats):
        solver = MazeSolver(maze, strategy)
        path, stats = solver.solve()
        
        times.append(stats.time_ms)
        visited_counts.append(stats.visited_cells)
        path_lengths.append(stats.path_length)
        path_found = stats.path_found
    
    return {
        'strategy': strategy_name,
        'time_mean': sum(times) / len(times),
        'time_min': min(times),
        'time_max': max(times),
        'visited_mean': sum(visited_counts) / len(visited_counts),
        'path_length_mean': sum(path_lengths) / len(path_lengths) if path_found else 0,
        'path_found': path_found
    }


def run_all_experiments(maze_files: List[str], repeats: int = 5) -> List[Dict]:
    """Запускает эксперименты для всех лабиринтов и стратегий"""
    builder = TextFileMazeBuilder()
    strategies = [
        ('BFS', BFSStrategy()),
        ('DFS', DFSStrategy()),
        ('A*', AStarStrategy())
    ]
    
    results = []
    
    for maze_file in maze_files:
        try:
            maze = builder.build_from_file(maze_file)
        except (ValueError, FileNotFoundError) as e:
            print(f"❌ Ошибка: {e}")
            continue
        
        print(f"\n📊 Лабиринт: {maze_file}")
        print(f"   Размер: {maze.width}×{maze.height}")
        print(f"   Старт: ({maze.start.x}, {maze.start.y})")
        print(f"   Выход: ({maze.exit.x}, {maze.exit.y})")
        
        for strategy_name, strategy in strategies:
            print(f"   🧪 Тестирование: {strategy_name}")
            result = run_experiment(maze, strategy_name, strategy, repeats)
            result['maze_file'] = maze_file.split('/')[-1]
            result['maze_size'] = f"{maze.width}×{maze.height}"
            results.append(result)
            
            status = "✅" if result['path_found'] else "❌"
            print(f"       {status} Время: {result['time_mean']:.2f} мс, "
                  f"Посещено: {result['visited_mean']:.0f}, "
                  f"Путь: {result['path_length_mean']:.0f}")
    
    return results


def save_results_to_csv(results: List[Dict], filename: str = "experiment_results.csv") -> None:
    """Сохраняет результаты в CSV файл"""
    with open(filename, 'w', newline='', encoding='utf-8') as f:
        writer = csv.DictWriter(f, fieldnames=[
            'maze_file', 'maze_size', 'strategy',
            'time_mean', 'time_min', 'time_max',
            'visited_mean', 'path_length_mean', 'path_found'
        ])
        writer.writeheader()
        writer.writerows(results)
    print(f"\n💾 Результаты сохранены в {filename}")


def print_results_table(results: List[Dict]) -> None:
    """Выводит результаты в виде таблицы"""
    print("\n" + "=" * 80)
    print("РЕЗУЛЬТАТЫ ЭКСПЕРИМЕНТОВ")
    print("=" * 80)
    
    for res in results:
        print(f"\n📁 Лабиринт: {res['maze_file']}")
        print(f"   📐 Размер: {res['maze_size']}")
        print(f"   🎯 Стратегия: {res['strategy']}")
        print(f"   ⏱️  Время (ср):   {res['time_mean']:.2f} мс")
        print(f"   📍 Посещено:     {res['visited_mean']:.0f} клеток")
        print(f"   🛤️  Длина пути:   {res['path_length_mean']:.0f}")