import json
import logging
import os
from collections import defaultdict
from datetime import datetime
from typing import Dict, List, Tuple

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')


class TestResult:
    """Represents a single test result."""

    def __init__(self, test_type: str, test_name: str, status: str, duration: float, error_message: str = None):
        """
        Initializes a TestResult object.

        Args:
            test_type: The type of test (e.g., "unit", "integration").
            test_name: The name of the test.
            status: The status of the test ("passed", "failed", "skipped").
            duration: The duration of the test in seconds.
            error_message: An optional error message if the test failed.
        """
        self.test_type = test_type
        self.test_name = test_name
        self.status = status
        self.duration = duration
        self.error_message = error_message

    def __repr__(self):
        return f"TestResult(test_type='{self.test_type}', test_name='{self.test_name}', status='{self.status}', duration={self.duration})"


class TestReportGenerator:
    """Generates unified test reports from various test suites."""

    def __init__(self, report_dir: str = "reports"):
        """
        Initializes the TestReportGenerator.

        Args:
            report_dir: The directory to store the generated reports.
        """
        self.report_dir = report_dir
        os.makedirs(self.report_dir, exist_ok=True)
        self.test_results: List[TestResult] = []

    def load_test_results(self, result_files: List[str]):
        """
        Loads test results from JSON files.

        Args:
            result_files: A list of paths to JSON files containing test results.
        """
        for file_path in result_files:
            try:
                with open(file_path, "r") as f:
                    data = json.load(f)
                    for item in data:
                        try:
                            result = TestResult(
                                test_type=item["test_type"],
                                test_name=item["test_name"],
                                status=item["status"],
                                duration=item["duration"],
                                error_message=item.get("error_message")
                            )
                            self.test_results.append(result)
                        except KeyError as e:
                            logging.error(f"Missing key in test result: {e} in file {file_path}")
                        except Exception as e:
                            logging.error(f"Error processing test result: {e} in file {file_path}")

            except FileNotFoundError:
                logging.error(f"File not found: {file_path}")
            except json.JSONDecodeError:
                logging.error(f"Invalid JSON format in file: {file_path}")
            except Exception as e:
                logging.error(f"Error loading test results from file {file_path}: {e}")

    def calculate_overall_health_score(self) -> float:
        """
        Calculates the overall health score based on the test results.

        Returns:
            The overall health score as a float (0.0 to 1.0).
        """
        if not self.test_results:
            return 1.0  # If no tests were run, consider it healthy

        passed_count = sum(1 for result in self.test_results if result.status == "passed")
        total_count = len(self.test_results)
        return passed_count / total_count

    def generate_html_report(self, output_file: str = "report.html"):
        """
        Generates an HTML report of the test results.

        Args:
            output_file: The name of the output HTML file.
        """
        try:
            health_score = self.calculate_overall_health_score()
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

            html_content = f"""
            <!DOCTYPE html>
            <html>
            <head>
                <title>Test Report</title>
                <style>
                    body {{ font-family: Arial, sans-serif; }}
                    table {{ width: 100%; border-collapse: collapse; }}
                    th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
                    th {{ background-color: #f2f2f2; }}
                    .passed {{ color: green; }}
                    .failed {{ color: red; }}
                    .skipped {{ color: orange; }}
                </style>
            </head>
            <body>
                <h1>Test Report</h1>
                <p>Generated on: {timestamp}</p>
                <p>Overall Health Score: {health_score:.2f}</p>
                <table>
                    <thead>
                        <tr>
                            <th>Test Type</th>
                            <th>Test Name</th>
                            <th>Status</th>
                            <th>Duration (s)</th>
                            <th>Error Message</th>
                        </tr>
                    </thead>
                    <tbody>
            """

            for result in self.test_results:
                status_class = result.status.lower()
                html_content += f"""
                        <tr>
                            <td>{result.test_type}</td>
                            <td>{result.test_name}</td>
                            <td class="{status_class}">{result.status}</td>
                            <td>{result.duration:.4f}</td>
                            <td>{result.error_message if result.error_message else ""}</td>
                        </tr>
                """

            html_content += """
                    </tbody>
                </table>
            </body>
            </html>
            """

            output_path = os.path.join(self.report_dir, output_file)
            with open(output_path, "w") as f:
                f.write(html_content)

            logging.info(f"HTML report generated at: {output_path}")

        except Exception as e:
            logging.error(f"Error generating HTML report: {e}")

    def generate_markdown_report(self, output_file: str = "report.md"):
        """
        Generates a Markdown report of the test results.

        Args:
            output_file: The name of the output Markdown file.
        """
        try:
            health_score = self.calculate_overall_health_score()
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

            markdown_content = f"""
            # Test Report

            Generated on: {timestamp}

            Overall Health Score: {health_score:.2f}

            | Test Type | Test Name | Status | Duration (s) | Error Message |
            |---|---|---|---|---|
            """

            for result in self.test_results:
                markdown_content += f"""
            | {result.test_type} | {result.test_name} | {result.status} | {result.duration:.4f} | {result.error_message if result.error_message else ""} |
            """

            output_path = os.path.join(self.report_dir, output_file)
            with open(output_path, "w") as f:
                f.write(markdown_content)

            logging.info(f"Markdown report generated at: {output_path}")

        except Exception as e:
            logging.error(f"Error generating Markdown report: {e}")

    def generate_unified_report(self, result_files: List[str], html_output: str = "report.html", md_output: str = "report.md"):
        """
        Generates both HTML and Markdown reports.

        Args:
            result_files: A list of paths to JSON files containing test results.
            html_output: The name of the output HTML file.
            md_output: The name of the output Markdown file.
        """
        self.load_test_results(result_files)
        self.generate_html_report(html_output)
        self.generate_markdown_report(md_output)


if __name__ == "__main__":
    # Example usage:
    # Create dummy test result files
    os.makedirs("test_results", exist_ok=True)
    with open("test_results/unit_tests.json", "w") as f:
        json.dump([
            {"test_type": "unit", "test_name": "test_addition", "status": "passed", "duration": 0.01},
            {"test_type": "unit", "test_name": "test_subtraction", "status": "failed", "duration": 0.02, "error_message": "Assertion failed"},
        ], f)
    with open("test_results/integration_tests.json", "w") as f:
        json.dump([
            {"test_type": "integration", "test_name": "test_db_connection", "status": "passed", "duration": 0.5},
            {"test_type": "integration", "test_name": "test_api_call", "status": "skipped", "duration": 0.1},
        ], f)

    # Generate the report
    generator = TestReportGenerator()
    result_files = ["test_results/unit_tests.json", "test_results/integration_tests.json"]
    generator.generate_unified_report(result_files, html_output="unified_report.html", md_output="unified_report.md")

    # Clean up dummy files
    os.remove("test_results/unit_tests.json")
    os.remove("test_results/integration_tests.json")
    os.rmdir("test_results")
