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

plt.rcParams['font.size'] = 10
plt.rcParams['font.family'] = 'sans-serif'

def plot_results(csv_file="docs/data/results.csv"):
    if not os.path.exists(csv_file):
        print(f"Файл {csv_file} не найден. Сначала запустите benchmark.py")
        return
    
    data = {}
    
    with open(csv_file, 'r', encoding='utf-8') as f:
        reader = csv.reader(f)
        next(reader)
        for row in reader:
            if len(row) < 5:
                continue
            struct, mode, op, _, time_val = row
            try:
                time_val = float(time_val)
            except:
                continue
            
            if struct not in data:
                data[struct] = {}
            if mode not in data[struct]:
                data[struct][mode] = {}
            if op not in data[struct][mode]:
                data[struct][mode][op] = []
            data[struct][mode][op].append(time_val)
    
    operations = ['вставка', 'поиск', 'удаление']
    op_names = ['Вставка', 'Поиск', 'Удаление']
    structures = ['LinkedList', 'HashTable', 'BST']
    modes = ['случайный', 'отсортированный']
    colors = {'LinkedList': '#3498db', 'HashTable': '#2ecc71', 'BST': '#e74c3c'}
    
    fig, axes = plt.subplots(1, 3, figsize=(14, 5))
    fig.suptitle('Сравнение производительности структур данных\n(500 записей, 3 повторения)', fontsize=14, fontweight='bold')
    
    for idx, (op, op_name) in enumerate(zip(operations, op_names)):
        ax = axes[idx]
        x_positions = []
        labels = []
        values = []
        errors = []
        colors_list = []
        
        position = 0
        for struct in structures:
            for mode in modes:
                if struct in data and mode in data[struct] and op in data[struct][mode]:
                    times = data[struct][mode][op]
                    if times:
                        avg_time = np.mean(times)
                        std_time = np.std(times) if len(times) > 1 else 0
                        
                        x_positions.append(position)
                        labels.append(f'{struct}\n({mode[:4]})')
                        values.append(avg_time)
                        errors.append(std_time)
                        colors_list.append(colors[struct])
                        position += 1
        
        bars = ax.bar(x_positions, values, yerr=errors, capsize=5, color=colors_list, alpha=0.8, edgecolor='black', linewidth=0.5)
        ax.set_xticks(x_positions)
        ax.set_xticklabels(labels, fontsize=8, rotation=45, ha='right')
        ax.set_ylabel('Время (секунды)', fontsize=10)
        ax.set_title(f'{op_name}', fontsize=12, fontweight='bold')
        ax.grid(True, alpha=0.3, axis='y')
        
        for bar, val in zip(bars, values):
            if val > 0:
                height = bar.get_height()
                ax.text(bar.get_x() + bar.get_width()/2., height + max(values)*0.02,
                        f'{val:.4f}', ha='center', va='bottom', fontsize=7, rotation=0)
    
    plt.tight_layout()
    plt.savefig('docs/data/performance_graphs.png', dpi=300, bbox_inches='tight')
    plt.show()
    
    fig2, ax2 = plt.subplots(figsize=(10, 6))
    fig2.suptitle('Влияние порядка данных на производительность BST', fontsize=14, fontweight='bold')
    
    if 'BST' in data:
        bst_data = data['BST']
        x_pos = []
        labels = []
        random_vals = []
        sorted_vals = []
        
        for idx, op in enumerate(operations):
            random_time = 0
            sorted_time = 0
            
            if 'случайный' in bst_data and op in bst_data['случайный']:
                random_time = np.mean(bst_data['случайный'][op])
            if 'отсортированный' in bst_data and op in bst_data['отсортированный']:
                sorted_time = np.mean(bst_data['отсортированный'][op])
            
            x_pos.append(idx)
            x_pos.append(idx + 0.35)
            labels.append(op)
            random_vals.append(random_time)
            sorted_vals.append(sorted_time)
        
        width = 0.35
        bars1 = ax2.bar([i - width/2 for i in range(len(operations))], random_vals, width, 
                        label='Случайный порядок', color='#2ecc71', alpha=0.8, edgecolor='black')
        bars2 = ax2.bar([i + width/2 for i in range(len(operations))], sorted_vals, width,
                        label='Отсортированный порядок', color='#e74c3c', alpha=0.8, edgecolor='black')
        
        ax2.set_xticks(range(len(operations)))
        ax2.set_xticklabels(['Вставка', 'Поиск', 'Удаление'], fontsize=10)
        ax2.set_ylabel('Время (секунды)', fontsize=10)
        ax2.set_xlabel('Операция', fontsize=10)
        ax2.legend(fontsize=10)
        ax2.grid(True, alpha=0.3, axis='y')
        
        for bar, val in zip(bars1, random_vals):
            if val > 0:
                ax2.text(bar.get_x() + bar.get_width()/2., bar.get_height() + max(random_vals + sorted_vals)*0.02,
                        f'{val:.4f}', ha='center', va='bottom', fontsize=8)
        
        for bar, val in zip(bars2, sorted_vals):
            if val > 0:
                ax2.text(bar.get_x() + bar.get_width()/2., bar.get_height() + max(random_vals + sorted_vals)*0.02,
                        f'{val:.4f}', ha='center', va='bottom', fontsize=8)
    
    plt.tight_layout()
    plt.savefig('docs/data/bst_comparison.png', dpi=300, bbox_inches='tight')
    plt.show()
    
    print("\n" + "="*60)
    print("ИТОГОВАЯ ТАБЛИЦА РЕЗУЛЬТАТОВ")
    print("="*60)
    print(f"{'Структура':<15} {'Режим':<12} {'Вставка':<12} {'Поиск':<12} {'Удаление':<12}")
    print("-"*60)
    
    for struct in structures:
        for mode in modes:
            if struct in data and mode in data[struct]:
                insert_times = data[struct][mode].get('вставка', [0])
                find_times = data[struct][mode].get('поиск', [0])
                delete_times = data[struct][mode].get('удаление', [0])
                
                insert_avg = np.mean(insert_times) if insert_times else 0
                find_avg = np.mean(find_times) if find_times else 0
                delete_avg = np.mean(delete_times) if delete_times else 0
                
                print(f"{struct:<15} {mode:<12} {insert_avg:<12.6f} {find_avg:<12.6f} {delete_avg:<12.6f}")
    
    print("="*60)

if __name__ == "__main__":
    plot_results()