import logging
import os
from typing import Dict, Any, List
from datetime import datetime
from py_markdown_table.markdown_table import markdown_table

class ReportGenerator:
    """Генератор отчетов в формате Markdown."""

    def __init__(self):
        self.logger = logging.getLogger(__name__)

    def generate_benchmark_report(self, results: Dict[str, Any], output_dir: str = "results", model_name: str = None) -> str:
        """
        Генерация отчета для одного бенчмарка.

        Args:
            results: Результаты бенчмарка
            output_dir: Директория для сохранения отчета
            model_name: Имя модели (для структурирования результатов)

        Returns:
            Путь к сгенерированному файлу
        """
        if model_name:
            model_dir = os.path.join(output_dir, model_name)
            os.makedirs(model_dir, exist_ok=True)
            output_dir = model_dir

        os.makedirs(output_dir, exist_ok=True)
        filename = f"{results['benchmark_name']}.md"
        file_path = os.path.join(output_dir, filename)

        with open(file_path, 'w', encoding='utf-8') as f:
            f.write(f"# Отчет бенчмарка: {results['benchmark_name']}\n\n")
            f.write(f"**Дата:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
            f.write(f"**Общее количество тестов:** {results['total_tests']}\n\n")
            f.write(f"**Успешно выполнено:** {results['successful_tests']}\n\n")

            # Таблица с результатами
            table_data = [
                {
                    "Тест": "Тест",
                    "F1-Score": "F1-Score",
                    "Levenshtein": "Levenshtein",
                    "BLEU": "BLEU",
                    "ROUGE-1": "ROUGE-1",
                    "ROUGE-2": "ROUGE-2",
                    "ROUGE-L": "ROUGE-L",
                    "Code Similarity": "Code Similarity",
                    "Время (с)": "Время (с)"
                }
            ]

            for result in results['results']:
                if 'error' in result:
                    table_data.append({
                        "Тест": result['test_case'],
                        "F1-Score": "Ошибка",
                        "Levenshtein": "-",
                        "BLEU": "-",
                        "ROUGE-1": "-",
                        "ROUGE-2": "-",
                        "ROUGE-L": "-",
                        "Code Similarity": "-",
                        "Время (с)": "-"
                    })
                else:
                    # Извлекаем все метрики из результата
                    f1_score = result.get('f1_score', result.get('score', 0))
                    levenshtein = result.get('normalized_levenshtein', 0)
                    bleu = result.get('bleu_score', 0)
                    rouge_scores = result.get('rouge_scores', {})
                    code_sim = result.get('code_similarity', 0)

                    table_data.append({
                        "Тест": result['test_case'],
                        "F1-Score": f"{f1_score:.3f}" if f1_score else "-",
                        "Levenshtein": f"{levenshtein:.3f}" if levenshtein else "-",
                        "BLEU": f"{bleu:.3f}" if bleu else "-",
                        "ROUGE-1": f"{rouge_scores.get('rouge1', 0):.3f}" if rouge_scores else "-",
                        "ROUGE-2": f"{rouge_scores.get('rouge2', 0):.3f}" if rouge_scores else "-",
                        "ROUGE-L": f"{rouge_scores.get('rougeL', 0):.3f}" if rouge_scores else "-",
                        "Code Similarity": f"{code_sim:.3f}" if code_sim else "-",
                        "Время (с)": f"{result['latency']:.2f}"
                    })

            f.write("## Результаты тестов\n\n")
            f.write("| Тест | F1-Score | Levenshtein | BLEU | ROUGE-1 | ROUGE-2 | ROUGE-L | Code Similarity | Время (с) |\n")
            f.write("|--|--|--|--|--|--|--|--|--|\n")

            for result in results['results']:
                if 'error' in result:
                    f.write(f"| {result['test_case']} | Ошибка | - | - | - | - | - | - | - |\n")
                else:
                    # Извлекаем все метрики из результата
                    f1_score = result.get('f1_score', result.get('score', 0))
                    levenshtein = result.get('normalized_levenshtein', 0)
                    bleu = result.get('bleu_score', 0)
                    rouge_scores = result.get('rouge_scores', {})
                    code_sim = result.get('code_similarity', 0)

                    f1_score_display = f"{f1_score:.3f}" if f1_score else "-"
                    levenshtein_display = f"{levenshtein:.3f}" if levenshtein else "-"
                    bleu_display = f"{bleu:.3f}" if bleu else "-"
                    rouge1_display = f"{rouge_scores.get('rouge1', 0):.3f}" if rouge_scores else "-"
                    rouge2_display = f"{rouge_scores.get('rouge2', 0):.3f}" if rouge_scores else "-"
                    rougeL_display = f"{rouge_scores.get('rougeL', 0):.3f}" if rouge_scores else "-"
                    code_sim_display = f"{code_sim:.3f}" if code_sim else "-"

                    f.write(f"| {result['test_case']} | "
                          f"{f1_score_display} | "
                          f"{levenshtein_display} | "
                          f"{bleu_display} | "
                          f"{rouge1_display} | "
                          f"{rouge2_display} | "
                          f"{rougeL_display} | "
                          f"{code_sim_display} | "
                          f"{result['latency']:.2f} |\n")

            f.write("\n\n")

            # Сохранение request-response в лог
            if model_name:
                logs_dir = os.path.join(output_dir, "logs")
                os.makedirs(logs_dir, exist_ok=True)
                for result in results['results']:
                    if 'error' in result:
                        continue
                    log_filename = os.path.join(logs_dir, f"{results['benchmark_name']}_{result['test_case']}.txt")
                    with open(log_filename, 'w', encoding='utf-8') as log_file:
                        log_file.write(f"Промпт:\n{result['prompt']}\n\n")
                        log_file.write(f"Ответ модели:\n{result['model_response']}\n\n")
                        log_file.write(f"Ожидаемый ответ:\n{result['expected']}\n")

            # Статистика
            successful = [r for r in results['results'] if 'score' in r]
            if successful:
                avg_score = sum(r['score'] for r in successful) / len(successful)
                avg_latency = sum(r['latency'] for r in successful) / len(successful)

                f.write("## Статистика\n\n")
                f.write(f"- **Средний скор:** {avg_score:.3f}\n")
                f.write(f"- **Среднее время ответа:** {avg_latency:.3f} секунд\n")

        self.logger.info(f"Report saved to {file_path}")
        return file_path

    def generate_summary_report(self, all_results: List[Dict[str, Any]], output_dir: str = "results", model_name: str = None, ollama_url: str = None) -> str:
        """
        Генерация сводного отчета по всем бенчмаркам.

        Args:
            all_results: Список результатов всех бенчмарков
            output_dir: Директория для сохранения отчета
            model_name: Имя модели (для структурирования результатов)
            ollama_url: URL сервера Ollama

        Returns:
            Путь к сгенерированному файлу
        """
        if model_name:
            model_dir = os.path.join(output_dir, model_name)
            os.makedirs(model_dir, exist_ok=True)
            output_dir = model_dir

        os.makedirs(output_dir, exist_ok=True)
        filename = f"summary.md"
        file_path = os.path.join(output_dir, filename)

        with open(file_path, 'w', encoding='utf-8') as f:
            f.write("# Сводный отчет по всем бенчмаркам\n\n")
            f.write(f"**Дата:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
            if model_name:
                f.write(f"**Модель:** {model_name}\n\n")
            if ollama_url:
                f.write(f"**Ollama URL:** {ollama_url}\n\n")

            # Таблица с общими результатами
            table_data = [
                {
                    "Бенчмарк": "Бенчмарк",
                    "Тестов": "Тестов",
                    "Успешно": "Успешно",
                    "Средний скор": "Средний скор",
                    "Среднее время": "Среднее время"
                }
            ]

            for result in all_results:
                successful = [r for r in result['results'] if 'score' in r]
                avg_score = sum(r['score'] for r in successful) / len(successful) if successful else 0
                avg_latency = sum(r['latency'] for r in successful) / len(successful) if successful else 0

                table_data.append({
                    "Бенчмарк": result['benchmark_name'],
                    "Тестов": str(result['total_tests']),
                    "Успешно": str(result['successful_tests']),
                    "Средний скор": f"{avg_score:.3f}" if successful else "0",
                    "Среднее время": f"{avg_latency:.3f}" if successful else "0"
                })

            f.write("## Общие результаты\n\n")
            f.write("| Бенчмарк | Тестов | Успешно | Средний скор | Среднее время |\n")
            f.write("|--|--|--|--|--|\n")

            for result in all_results:
                successful = [r for r in result['results'] if 'score' in r]
                avg_score = sum(r['score'] for r in successful) / len(successful) if successful else 0
                avg_latency = sum(r['latency'] for r in successful) / len(successful) if successful else 0

                f.write(f"| {result['benchmark_name']} | {result['total_tests']} | {result['successful_tests']} | {avg_score:.3f} | {avg_latency:.3f} |\n")

            f.write("\n\n")

            # Подробности по каждому бенчмарку
            f.write("## Подробности\n\n")
            for result in all_results:
                f.write(f"### {result['benchmark_name']}\n\n")
                f.write(f"- **Тестов:** {result['total_tests']}\n")
                f.write(f"- **Успешно:** {result['successful_tests']}\n")

                successful = [r for r in result['results'] if 'score' in r]
                if successful:
                    avg_score = sum(r['score'] for r in successful) / len(successful)
                    avg_latency = sum(r['latency'] for r in successful) / len(successful)
                    f.write(f"- **Средний скор:** {avg_score:.3f}\n")
                    f.write(f"- **Среднее время:** {avg_latency:.3f} секунд\n")
                f.write("\n")

        self.logger.info(f"Summary report saved to {file_path}")
        return file_path
